The Miami Beach Journal uses Claude to generate draft articles from city commission agendas. Feed in the item details and supporting PDFs, get a journalist-style draft. It works for pre-meeting previews -- but the articles always missed the most important part: what actually happened in the room.

Democracy.cc already had the transcripts -- diarized, speaker-labeled, with AI summaries. The data existed. It just wasn't connected.

Two New API Endpoints

I added two endpoints to Democracy.cc's admin API:

// Full diarized transcript for a specific agenda item
GET /api/admin/agenda-items/{id}/transcript

// Lightweight check: which items in a meeting have transcripts
GET /api/admin/meetings/{id}/transcript-status

The transcript endpoint merges consecutive same-speaker segments into natural turns and returns both formatted text and structured metadata:

{
  "has_transcript": true,
  "word_count": 8200,
  "speakers": ["Commissioner Smith", "Commissioner Jones", "City Attorney"],
  "transcript_text": "[Commissioner Smith]: I move to approve...",
  "summary": {
    "key_points": ["..."],
    "speakers_positions": ["..."],
    "decision": "Approved 5-2"
  }
}

Getting Good Quotes

The hardest part wasn't the plumbing -- it was getting Claude to use transcripts well. Raw transcripts are messy. People interrupt, go off-topic, make procedural motions. Dumping 8,000 words into the prompt produces articles stuffed with generic quotes.

The prompt structures the transcript with explicit guidance:

MEETING TRANSCRIPT:
Speaker labels identify participants. Use direct quotes when they add value.
Prefer substantive quotes that reveal positions, not procedural statements.
Balance quotes across different perspectives when multiple viewpoints exist.

For long discussions (45+ minutes), I truncate to the first and last 15,000 characters -- capturing initial presentation and final vote -- with the full AI summary always included so Claude has the complete picture.

Graceful Degradation

The integration can fail at multiple points -- API down, transcript missing, malformed data. None should prevent article generation. The fetch returns null on failure, the generation methods treat transcript as optional, and the UI only shows the transcript checkbox when one exists. If anything breaks, editors get exactly the article they would have gotten before.

The agenda says what was proposed. The transcript says what people thought about it. Connecting them produces something more valuable than either alone.