Enhance Meeting Minutes
This skill should be used when enhancing FHIR meeting minutes by synthesizing transcript discussion into Confluence pages, capturing reasoning and trade-offs with XML DOM manipulation
$ Installieren
git clone https://github.com/jmandel/enhance-meeting-minutes.skill ~/.claude/skills/enhance-meeting-minutes-skill// tip: Run this command in your terminal to install the skill
name: Enhance Meeting Minutes description: This skill should be used when enhancing FHIR meeting minutes by synthesizing transcript discussion into Confluence pages, capturing reasoning and trade-offs with XML DOM manipulation version: 1.0.0 dependencies: python>=3.8, lxml>=4.9.0 license: MIT
Enhance Meeting Minutes
Overview
This skill enhances FHIR Infrastructure meeting minutes by adding detailed discussion context from transcripts to Confluence pages. The process emphasizes content synthesis over transcription and XML DOM manipulation over string operations.
When to Use This Skill
This skill should be used when:
- Enhancing meeting minutes with transcript discussion
- Adding discussion details to Confluence pages
- Updating minutes with what was actually discussed
- Creating detailed minutes from meeting transcript
Required Inputs
This skill requires:
- Transcript file: Plain text transcript of the meeting
- Confluence page URL: URL to the meeting minutes page to enhance
.envfile: Contains API credentials for Confluence (and optionally JIRA)
Core Principles
Source of Truth Hierarchy
- Transcript: What was actually discussed today (absolute source of truth)
- Original Minutes: Structure and metadata only (attendees, JIRA widgets)
- JIRA Issues: Background context ONLY (never claim these were discussed today)
Content Philosophy
To create effective enhanced minutes:
- Create high-level narratives capturing WHY decisions were made
- Explain trade-offs and alternatives considered
- Show areas of agreement, disagreement, or things left open
- Focus on reasoning and substance
To avoid poor quality output:
- Avoid transcribing conversations verbatim or play-by-play
- Avoid quoting extensively (synthesize instead)
- Avoid using JIRA content as if discussed today
- Avoid writing shallow summaries without reasoning
Technical Philosophy
To build HTML correctly:
- Use XML DOM manipulation (lxml) for ALL HTML construction
- Avoid regex or string operations to build/modify HTML
ONE EXCEPTION: Post-process lxml output for XHTML self-closing tags (br/hr/col). This is the only acceptable string manipulation.
Complete Workflow
Phase 1: Gather Context (30-60 minutes)
Download Confluence Page
To download the current Confluence page, use scripts/confluence_api.py:
# From URL (automatically extracts page ID)
python scripts/confluence_api.py "https://confluence.hl7.org/display/FHIR/Minutes"
# From page ID directly
python scripts/confluence_api.py 123456
Output: current_page.json with HTML and version number
API endpoint: GET /rest/api/content/{pageId}?expand=body.storage,version
Download JIRA Issues for Background
To gather background context on JIRA issues, use scripts/jira_api.py:
# Download issue JSON
python scripts/jira_api.py FHIR-12345
# Create markdown background summary
python scripts/jira_api.py FHIR-12345 --background
Output:
FHIR-12345.json- Full issue dataFHIR-12345-background.md- Background summary
API endpoint: GET /rest/api/2/issue/{issueKey} (works unauthenticated for HL7)
CRITICAL: This provides background context ONLY. Never claim JIRA content was discussed today.
Read Transcript Carefully
To understand what actually happened in the meeting:
- Spend 20-40 minutes reading the transcript carefully
- Note which issues were discussed
- Identify where substantive discussion occurred
- Mark key moments of decision or debate
- Record timestamps for reference
DO NOT SKIP THIS STEP. This is where understanding of actual meeting discussion occurs.
Phase 2: Extract JIRA Widgets (5 minutes)
To preserve JIRA widgets from the original page, use scripts/extract_jira_widgets.py:
python scripts/extract_jira_widgets.py current_page.json
Output: jira_widgets.json - Mapping of issue keys to widget HTML
What this does:
- Parses original HTML with lxml
- Finds
<ac:structured-macro ac:name="jira">elements - Serializes widgets as HTML strings for re-insertion
In Python:
from extract_jira_widgets import extract_jira_widgets, get_widget_element
widgets = extract_jira_widgets(html_content)
widget_elem = get_widget_element(widgets['FHIR-12345'])
Phase 3: Analyze Transcript (60-120 minutes) ⭐ MOST IMPORTANT
To extract substance from the transcript, analyze each issue discussed by identifying:
- What sparked the discussion? - Context and trigger
- Key perspectives expressed - Different viewpoints
- Trade-offs and alternatives - Options considered with pros/cons
- Reasoning behind decision - WHY was it decided this way?
- Areas of agreement - What was uncontroversial
- Areas of disagreement - Concerns or debate
- Things left open - Deferred decisions or follow-ups
- Decision or outcome - What was actually decided
Time investment: Allocate 15-30 minutes per issue. Going faster indicates insufficient depth.
Create working notes for each issue capturing these elements. Avoid rushing this phase.
Phase 4: Draft Enhanced Content (30-60 minutes)
To create final content, draft in Markdown first, then convert to HTML. For each issue:
Content Structure
## FHIR-12345
### Discussion
[Opening paragraph: What was discussed? What sparked it?]
[Body paragraphs: Synthesize key points, perspectives, and reasoning]
The discussion centered on [main topic]. [Participants/The team]
emphasized [key perspective], noting that [reasoning]. However,
[alternative perspective] was also raised regarding [aspect].
Several approaches were considered:
- Approach A: [benefit] but [drawback]
- Approach B: [benefit] but [drawback]
The team decided to [decision], based primarily on [reasoning].
This approach was favored because [why it addresses concerns].
[Note any remaining concerns or open issues].
Style Guidelines
Voice and Tense:
- Use past tense: "The team discussed" not "The team discusses"
- Use third person: "Participants noted" not "We noted"
- Maintain professional but conversational tone
Focus on WHY:
- Insufficient: "Decided to use approach B."
- Effective: "Decided to use approach B primarily due to production stability concerns, though this may result in slower recovery from transient failures."
Synthesis, Not Transcription:
- Insufficient: "John said X. Then Mary said Y. Bob agreed."
- Effective: "The team weighed two approaches. Approach X offered [benefit] but raised concerns about [issue]. Approach Y provided [different benefit]."
Length: Aim for 2-4 substantive paragraphs per issue. One-paragraph summaries lack sufficient depth.
Phase 5: Build HTML with XML DOM (15-30 minutes)
To convert markdown drafts to HTML and assemble the complete document, use scripts/markdown_to_html.py and scripts/assemble_minutes.py:
#!/usr/bin/env python3
import sys
sys.path.insert(0, 'scripts')
from confluence_api import download_page
from extract_jira_widgets import extract_jira_widgets, get_widget_element
from markdown_to_html import parse_simple_markdown, create_issue_section
from assemble_minutes import build_complete_minutes
import json
# Load data
with open('current_page.json') as f:
page_data = json.load(f)
original_html = page_data['body']['storage']['value']
widgets = extract_jira_widgets(original_html)
# Build enhanced sections
enhanced_sections = []
for issue_key in ['FHIR-12345', 'FHIR-12346']: # Issue keys
# Read markdown draft
with open(f'{issue_key}-draft.md') as f:
draft_md = f.read()
# Parse to lxml elements
discussion_elems = parse_simple_markdown(draft_md)
# Get JIRA widget
widget = get_widget_element(widgets[issue_key])
# Create section
section = create_issue_section(issue_key, widget, discussion_elems)
enhanced_sections.extend(section)
# Assemble complete document
final_html = build_complete_minutes('current_page.json', enhanced_sections)
# Save
with open('enhanced_minutes.html', 'w') as f:
f.write(final_html)
Key functions available in scripts:
parse_simple_markdown(text)- Convert markdown to lxml elementscreate_heading(level, text)- Create h1-h6 elementcreate_paragraph(text)- Create p elementcreate_list(items, ordered=False)- Create ul/ol elementcreate_issue_section(key, widget, discussion_elems)- Complete issue sectionassemble_enhanced_minutes(original_html, enhanced_sections)- Preserve structurepost_process_for_xhtml(html)- Fix br/hr/col tags (the ONE exception)
Phase 6: Upload to Confluence (5 minutes)
To upload the enhanced minutes, use scripts/upload_to_confluence.py:
python scripts/upload_to_confluence.py \
<page_id> \
enhanced_minutes.html \
current_page.json
Requires environment: CONFLUENCE_URL, CONFLUENCE_USER, CONFLUENCE_TOKEN
In Python:
from upload_to_confluence import upload_from_file
response = upload_from_file(
page_id='123456',
html_file='enhanced_minutes.html',
current_version_file='current_page.json'
)
API endpoint: PUT /rest/api/content/{pageId}
To verify success, check output for HTTP 200 and new version number.
Time Investment
Expected time allocation per phase:
- Phase 1 (Context): 30-60 min
- Phase 2 (Widgets): 5 min
- Phase 3 (Analysis): 60-120 min ⭐ Most critical - avoid rushing
- Phase 4 (Drafting): 30-60 min
- Phase 5 (Building): 15-30 min
- Phase 6 (Upload): 5 min
Total: 2.5-4.5 hours
Most time should be in Phases 3-4 (content work). Spending more time on technical work than content work indicates incorrect prioritization.
Common Pitfalls to Avoid
Content Mistakes (CRITICAL)
-
Shallow summaries: "We discussed FHIR-12345 and decided to implement it."
- Solution: Add 2-4 paragraphs explaining WHY, trade-offs, reasoning
-
Conflating sources: Using JIRA decisions as if discussed today
- Solution: Use only transcript for today's discussion. JIRA is background only.
-
Over-quoting: Verbatim transcript with timestamps
- Solution: Synthesize ideas into narrative form
-
Missing WHY: Stating decisions without reasoning
- Solution: Always explain why decisions were made, what factors mattered
Technical Mistakes
-
String manipulation for HTML: Using regex/concat to build HTML
- Solution: Use lxml etree.Element() for all DOM construction
-
Forgetting deepcopy():
append()moves elements, not copies- Solution:
from copy import deepcopyand usedeepcopy(elem)when preserving
- Solution:
-
Removing JIRA widgets: Building content without preserving widgets
- Solution: Extract first, re-insert when building sections
-
Excessive post-processing: Using regex to fix structural issues
- Solution: Only post-process for XHTML self-closing tags (br/hr/col)
Success Criteria
To evaluate completion quality:
- Content Quality: Rich narratives with reasoning and trade-offs (2-4 paragraphs per issue)
- Technical Correctness: Valid XHTML that Confluence accepts
- Structure Preservation: All JIRA widgets and metadata intact
- Source Accuracy: Only transcript content presented as today's discussion
Scripts Reference
All scripts in scripts/ directory support:
- Standalone CLI usage
- Python module import
- Environment variable configuration via
.env
confluence_api.py
Download Confluence pages, extract page IDs from URLs
jira_api.py
Download JIRA issues (authenticated or public), create background files
extract_jira_widgets.py
Parse HTML, extract JIRA widgets for preservation
markdown_to_html.py
Convert markdown to lxml element trees with proper DOM construction
assemble_minutes.py
Assemble complete HTML preserving original structure using deepcopy()
upload_to_confluence.py
Upload to Confluence with error handling
Key Lessons
This workflow was developed through multiple failed iterations. The critical lessons learned:
- Content quality matters more than technical perfection - Perfect HTML with shallow content represents failure
- Transcript analysis cannot be rushed - 60-120 minutes minimum required for proper depth
- Synthesis is a skill - Practice capturing WHY not WHO
- XML DOM manipulation is non-negotiable - Avoid string operations for HTML
- User feedback is ultimate judge - Expect iteration
The biggest failure mode: Focusing on technical work while producing shallow content that fails to capture reasoning and trade-offs.
Repository
