name: podcast-audio-plan description: Generate audio and transcripts for podcast episodes from Fountain screenplays using Produciesta CLI. When asked to "generate podcast audio", "create audio plan", "cast voices", "prepare transcripts", or working with podcast projects that have episodes/*.fountain files, this skill analyzes characters, assigns voices, writes PROJECT.md cast list, generates audio, and prepares transcripts for web deployment.
Podcast Audio Generation with Produciesta
Generate professional podcast audio from Fountain screenplay files using Claude-assisted voice casting and Produciesta CLI generation.
When to Use This Skill
Use this skill when:
- User asks to generate audio for a podcast project
- Project has episode scripts in Fountain format (
episodes/*.fountain) - User wants to create or update a cast list in PROJECT.md
- User asks to "cast voices", "assign voices", "plan audio generation"
- User wants to generate audio from screenplays
What This Skill Does
This skill provides a Claude-assisted workflow for podcast audio generation and web publishing:
- Analyze Fountain files to extract character list
- Query available voices from Apple TTS or ElevenLabs
- Match characters to voices based on character traits and voice characteristics
- Write PROJECT.md with proper YAML front matter and cast list
- Generate audio using Produciesta CLI
- Commit audio to Git LFS and verify CDN availability
- Copy transcripts to website episodes directory
- Update website page with CDN links, metadata, and RSS feed
- Validate deployment (subscribe links, playback, transcripts)
- Deploy to production via git push
Prerequisites
Required Tools
- Produciesta CLI at
~/Projects/Produciesta/produciesta-cli/ - Swift 6.2+ (for building Produciesta if needed)
- Xcode 16+ (macOS only)
- Apple TTS (built-in macOS) or ElevenLabs API key
Project Structure
Podcast Source Repository (Produciesta project):
~/podcast-daily-dao/
├── PROJECT.md # Project configuration (Claude creates this)
├── episodes/ # Fountain screenplay files (source)
│ ├── chapter-01.fountain
│ ├── chapter-02.fountain
│ └── ...
├── audio/ # Generated audio files (Git LFS)
│ ├── chapter-01.m4a
│ ├── chapter-02.m4a
│ └── ...
└── .gitattributes # LFS configuration for *.m4a files
Website Repository (intrusive-memory.github.com):
~/Projects/intrusive-memory.github.com/podcasts/daily-dao/
├── index.html # Podcast player page
├── feed.xml # RSS feed
├── podcast-artwork.jpg # Cover art (3000x3000)
├── favicon.ico
├── apple-touch-icon.png
├── episodes/ # Transcripts (copied from source)
│ ├── chapter-01.fountain
│ ├── chapter-02.fountain
│ └── ...
└── audio/ # Placeholder or symlink (audio served from CDN)
Critical Separation:
- Source repo: Where audio is generated and stored (Git LFS)
- Website repo: Where podcast page lives and references CDN URLs
- CDN: Cloudflare R2 serves audio via
https://pub-8e049ed02be340cbb18f921765fd24f3.r2.dev/
Voice Casting Workflow (Claude-Assisted)
IMPORTANT: Produciesta's --autocast feature is currently not working. Instead, use Claude to create the cast list manually.
Step 1: Discover Episodes and Extract Characters
# List all Fountain files
ls episodes/*.fountain
# Read a sample episode to understand characters
cat episodes/chapter-01.fountain
Claude will:
- Read Fountain files to identify all CHARACTER names
- Analyze dialogue to understand character traits (age, gender, personality)
- Build a comprehensive character list
Step 2: Query Available Voices
For Apple TTS:
say -v '?'
For ElevenLabs:
# List available voices (if using ElevenLabs MCP)
# Or use: https://elevenlabs.io/docs/voices/voice-library
Claude will:
- Parse available voices and their characteristics
- Note voice IDs, names, languages, and qualities
Step 3: Match Characters to Voices
Claude will:
- Consider character traits from dialogue analysis
- Match each character to the most appropriate voice
- Provide primary and fallback voice options
- Explain the reasoning for each assignment
Step 4: Create or Update PROJECT.md
Claude will:
- Create PROJECT.md with proper YAML front matter
- Write the cast list with voice URIs
- Include episode count and configuration
- Add production notes for documentation
Example PROJECT.md:
---
type: project
title: My Podcast Series
author: Author Name
description: Description of the podcast
episodesDir: episodes
audioDir: audio
filePattern: "*.fountain"
exportFormat: m4a
cast:
- character: NARRATOR
voices:
- apple://com.apple.voice.premium.en-US.Aaron
- character: ALICE
voices:
- apple://com.apple.voice.premium.en-US.Ava
- character: BOB
voices:
- apple://com.apple.voice.premium.en-US.Daniel
---
## Production Notes
### Voice Casting
- NARRATOR: Aaron (mature, authoritative voice)
- ALICE: Ava (young female, clear diction)
- BOB: Daniel (British accent, professional tone)
### Project Structure
- 10 episodes in Fountain format
- Generated audio saved to `audio/` directory
- Format: M4A (Apple AAC)
Step 5: Generate Audio with Produciesta
# Generate audio using the cast list
produciesta /path/to/project --format m4a --verbose
What happens:
- ✅ Produciesta reads PROJECT.md cast list
- ✅ Parses Fountain files and resolves character voices
- ✅ Generates audio for all episodes
- ✅ Saves M4A files to
audio/directory
Voice Providers
Apple Neural TTS (Free)
Advantages:
- No API key required
- Premium voices included with macOS
- Fast, local processing
- No per-character costs
Best for: English podcasts, quick testing, budget projects
Query voices:
say -v '?'
Voice URI format:
apple://com.apple.voice.premium.en-US.Aaron
Popular voices:
- Aaron - Mature male, US accent
- Ava - Young female, US accent, clear
- Daniel - Male, British accent
- Samantha - Female, US accent, warm
- Fred - Male, novelty voice
- Zoe - Female, US accent, professional
ElevenLabs (Paid)
Advantages:
- Extremely natural-sounding voices
- Multilingual support
- Professional quality
- Emotion control
Best for: Professional production, non-English podcasts, high-quality output
Setup:
export ELEVENLABS_API_KEY="your-key-here"
Voice URI format:
elevenlabs://21m00Tcm4TlvDq8ikWAM
Popular voices:
21m00Tcm4TlvDq8ikWAM- Rachel (US female)EXAVITQu4vr4xnSDxMaL- Bella (US female)pNInz6obpgDQGcFmaJgB- Adam (US male)ErXwobaYiN019PkySvjV- Antoni (male, well-rounded)MF3mGyEYCl7XYWbV9V6O- Elli (young female)
Complete End-to-End Publishing Workflow
This is the complete workflow from .fountain files to live podcast on intrusive-memory.productions.
Prerequisites Checklist
Before starting, verify:
- Produciesta CLI built and working:
produciesta --version - Git LFS installed:
git lfs version - Website repo cloned:
~/Projects/intrusive-memory.github.com/ - Podcast source repo exists (or create new)
- CDN URL known:
https://pub-8e049ed02be340cbb18f921765fd24f3.r2.dev/
Scenario: Publishing Daily Dao Episodes 1-5
Variables for this example:
- Source repo:
~/podcast-daily-dao/ - Website repo:
~/Projects/intrusive-memory.github.com/ - Podcast slug:
daily-dao - Audio path on CDN:
daily-dao/(matches slug)
PHASE 1: Audio Generation (Source Repo)
Step 1: Analyze Episodes and Extract Characters
cd ~/podcast-daily-dao
ls episodes/*.fountain
# Output: chapter-01.fountain through chapter-05.fountain
Claude reads sample episodes and identifies:
- NARRATOR - Reads verses and commentary
Step 2: Query Available Voices
say -v '?'
Claude selects:
- NARRATOR → Aaron (mature, contemplative tone)
Step 3: Create PROJECT.md
---
type: project
title: Daily Dao - Tao De Jing Podcast
author: Tom Stovall
description: Daily readings from the Tao Te Ching with commentary
episodesDir: episodes
audioDir: audio
filePattern: "*.fountain"
exportFormat: m4a
cast:
- character: NARRATOR
voices:
- apple://com.apple.voice.premium.en-US.Aaron
---
## Production Notes
### Voice Casting
- NARRATOR: Aaron - Mature, authoritative voice appropriate for philosophical content
### Project Details
- Episodes 1-5 of the Tao Te Ching
- Each episode: ~4-6 minutes
Step 4: Generate Audio Files
produciesta . --format m4a --verbose
Output:
✓ Project directory: /Users/stovak/podcast-daily-dao
✓ Found 5 episodes
✓ Cast list loaded: 1 character
✓ Starting generation...
Episode 1/5: chapter-01.fountain
Parsing... ✓ 15 elements
Generating... ✓ 100%
Exporting... ✓ chapter-01.m4a (3.8 MB, 4m 45s)
[... episodes 2-4 ...]
Episode 5/5: chapter-05.fountain
Parsing... ✓ 14 elements
Generating... ✓ 100%
Exporting... ✓ chapter-05.m4a (3.5 MB, 4m 22s)
✓ Generation complete!
Processed: 5 episodes
Duration: 23m 12s total
Output: ~/podcast-daily-dao/audio/
Step 5: Verify Generated Audio
ls -lh audio/
# Should see: chapter-01.m4a through chapter-05.m4a
# Test playback of first episode
open audio/chapter-01.m4a
PHASE 2: Git LFS Commit (Source Repo)
Step 6: Configure Git LFS (if not already done)
# Check if LFS is tracking .m4a files
cat .gitattributes | grep m4a
# If not present, configure it:
echo "*.m4a filter=lfs diff=lfs merge=lfs -text" >> .gitattributes
git lfs track "*.m4a"
Step 7: Commit Audio Files to LFS
git add audio/*.m4a
git add .gitattributes
git commit -m "Add audio for chapters 1-5
- Generated with Produciesta using Aaron (Apple TTS)
- Total duration: 23m 12s
- Episodes: chapter-01 through chapter-05
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
git push origin main
Step 8: Verify LFS Upload
git lfs ls-files
# Should show: audio/chapter-01.m4a, chapter-02.m4a, etc.
# Verify files are uploaded to LFS (not stored as blobs)
git lfs status
Step 9: Verify CDN Availability
# Test that audio is accessible via CDN
curl -I https://pub-8e049ed02be340cbb18f921765fd24f3.r2.dev/daily-dao/chapter-01.m4a
# Should return: HTTP/2 200
# Content-Type: audio/mp4
If 404: Wait a few minutes for LFS sync to CDN, or check CDN configuration.
PHASE 3: Website Integration (Website Repo)
Step 10: Copy Transcripts to Website
cd ~/Projects/intrusive-memory.github.com
# Copy .fountain files to website episodes directory
cp ~/podcast-daily-dao/episodes/*.fountain \
podcasts/daily-dao/episodes/
# Verify copy
ls podcasts/daily-dao/episodes/
# Should see: chapter-01.fountain through chapter-05.fountain
Step 11: Update Website Metadata
Open podcasts/daily-dao/index.html and verify:
Check page title and description:
<div class="podcast-header">
<h1>Daily Dao</h1> <!-- ✓ Correct -->
<p>81 Chapters of the Tao Te Ching</p> <!-- ✓ Correct -->
Check CDN URLs in JavaScript:
audioSource.src = '{{ site.audio_cdn }}/daily-dao/chapter-01.m4a';
// ^^^^^^^^^ matches podcast slug
Check subscribe links:
<a href="podcast://intrusive-memory.productions/podcasts/daily-dao/feed.xml" class="subscribe-link podcast-app">Subscribe in Podcast App</a>
<a href="/podcasts/daily-dao/feed.xml" class="subscribe-link rss">RSS Feed</a>
Step 12: Update RSS Feed
Open podcasts/daily-dao/feed.xml and add episodes:
<item>
<title>Chapter 1 - The fundamental paradox of the Tao</title>
<description>Chapter One introduces us to the fundamental paradox of the Tao...</description>
<pubDate>Wed, 12 Feb 2025 00:00:00 -0500</pubDate>
<enclosure url="https://pub-8e049ed02be340cbb18f921765fd24f3.r2.dev/daily-dao/chapter-01.m4a"
length="3980000"
type="audio/mp4"/>
<guid>https://intrusive-memory.productions/podcasts/daily-dao/chapter-01</guid>
<itunes:duration>285</itunes:duration>
<itunes:episodeType>full</itunes:episodeType>
</item>
Get file size and duration:
# File size (bytes)
stat -f%z ~/podcast-daily-dao/audio/chapter-01.m4a
# Duration (seconds) - use afinfo on macOS
afinfo ~/podcast-daily-dao/audio/chapter-01.m4a | grep "estimated duration"
Step 13: Update Podcast Metadata
Update _data/podcasts.yml if episode count changed:
- slug: daily-dao
name: Daily Dao - Tao De Jing Podcast
episodes: 5 # ← Update this count
status: in_progress # or "complete" if all 81 done
published: true # Set to true when ready to go live
PHASE 4: Validation & Testing
Step 14: Test Locally with Jekyll
cd ~/Projects/intrusive-memory.github.com
# Start Jekyll server
bundle exec jekyll serve
# Visit: http://localhost:4000/podcasts/daily-dao/
Validate checklist:
- Page loads without errors
- Title and subhead are correct
- Audio player loads first episode
- Audio plays from CDN (check network tab)
- Transcript loads and displays correctly
- Chapter buttons work (switch episodes)
- Subscribe links point to correct URLs
- RSS feed validates (use https://validator.w3.org/feed/)
Step 15: Validate RSS Feed
# Validate feed structure
curl http://localhost:4000/podcasts/daily-dao/feed.xml | xmllint --format -
# Or use online validator:
# https://validator.w3.org/feed/
Check for:
- All episode
<enclosure>URLs point to CDN - File sizes are accurate
- Durations are in seconds
- Pub dates are valid RFC-822 format
Step 16: Test Transcripts
In browser console:
// Should load without errors
fetch('/podcasts/daily-dao/episodes/chapter-01.fountain')
.then(r => r.text())
.then(console.log);
Verify:
- .fountain files are accessible (not 404)
- Transcript content appears (no YAML/SSML tags)
- Switching episodes loads new transcripts
PHASE 5: Deployment
Step 17: Commit Website Changes
cd ~/Projects/intrusive-memory.github.com
git add podcasts/daily-dao/episodes/*.fountain
git add podcasts/daily-dao/feed.xml
git add podcasts/daily-dao/index.html # if modified
git add _data/podcasts.yml # if modified
git commit -m "Publish Daily Dao episodes 1-5
- Add transcripts for chapters 1-5
- Update RSS feed with new episodes
- Update episode count in podcasts.yml
- CDN audio URLs verified and working
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
Step 18: Push to Production
git push origin master
Step 19: Verify GitHub Pages Build
# Check build status (if gh CLI installed)
gh run list --limit 1
# Or visit: https://github.com/intrusive-memory/intrusive-memory.github.com/actions
Wait for:
- ✅ GitHub Pages build completes (~1-2 minutes)
- ✅ Changes deploy to production
Step 20: Final Production Validation
Visit live site: https://intrusive-memory.productions/podcasts/daily-dao/
Final checklist:
- Page loads on production
- Audio plays from CDN
- Transcripts display correctly
- Subscribe links work
- RSS feed accessible at
/podcasts/daily-dao/feed.xml - Test subscribe in podcast app (Apple Podcasts, Overcast, etc.)
Workflow Summary
┌─────────────────────────────────────────┐
│ PHASE 1: Audio Generation │
│ - Analyze .fountain files │
│ - Create PROJECT.md with cast │
│ - Generate audio with Produciesta │
│ - Verify playback locally │
└──────────────┬──────────────────────────┘
│
┌──────────────▼──────────────────────────┐
│ PHASE 2: Git LFS Commit │
│ - Configure LFS for .m4a │
│ - Commit audio files │
│ - Push to remote │
│ - Verify CDN availability │
└──────────────┬──────────────────────────┘
│
┌──────────────▼──────────────────────────┐
│ PHASE 3: Website Integration │
│ - Copy transcripts to website │
│ - Update index.html metadata │
│ - Update RSS feed with episodes │
│ - Update _data/podcasts.yml │
└──────────────┬──────────────────────────┘
│
┌──────────────▼──────────────────────────┐
│ PHASE 4: Validation & Testing │
│ - Test locally with Jekyll │
│ - Validate RSS feed │
│ - Check audio playback │
│ - Verify transcripts load │
└──────────────┬──────────────────────────┘
│
┌──────────────▼──────────────────────────┐
│ PHASE 5: Deployment │
│ - Commit website changes │
│ - Push to production │
│ - Verify GitHub Pages build │
│ - Final production validation │
└─────────────────────────────────────────┘
Time Estimate:
- Audio generation: ~2-3 minutes per episode
- LFS commit & CDN verify: 5-10 minutes
- Website updates: 10-15 minutes
- Testing & validation: 10-15 minutes
- Deployment: 5-10 minutes
- Total for 5 episodes: ~45-60 minutes
Character Analysis Guidelines
When analyzing Fountain files to extract characters, Claude should:
1. Identify All Characters
Parse Fountain dialogue blocks:
NARRATOR
This is the narrator speaking.
ALICE
Hello, I'm Alice!
BOB (V.O.)
And I'm Bob, off screen.
Extract: NARRATOR, ALICE, BOB
Note: Character name variations map to same character:
BOB,BOB (V.O.),BOB (O.S.),BOB (CONT'D)→ all =BOB
2. Analyze Character Traits
From dialogue and context, determine:
- Age range (child, young adult, middle-aged, elderly)
- Gender (male, female, neutral)
- Personality (authoritative, friendly, serious, playful)
- Role (narrator, protagonist, antagonist, supporting)
- Accent/dialect (if specified or implied)
3. Consider Dialogue Volume
Note how much each character speaks:
- Primary characters (lots of dialogue) → assign premium voices
- Supporting characters (moderate dialogue) → standard voices
- Minor characters (few lines) → can share voices or use default
4. Document Casting Rationale
In PROJECT.md production notes, explain:
- Why each voice was selected
- Character traits that influenced the choice
- Any special considerations
Voice Matching Guidelines
When matching characters to voices:
For Narrators
Ideal characteristics:
- Clear articulation
- Moderate pace
- Authoritative but not harsh
- Easy to listen to for extended periods
Recommended Apple voices:
- Aaron (US male, mature)
- Ava (US female, clear)
- Daniel (UK male, professional)
For Conversational Characters
Ideal characteristics:
- Natural, warm tone
- Expressive (can convey emotion)
- Distinct from other characters
Recommended Apple voices:
- Samantha (US female, friendly)
- Fred (US male, character voice)
- Zoe (US female, professional)
For ElevenLabs
Advantages:
- More emotional range
- Better for character voices
- Multilingual support
When to use:
- Professional productions
- Non-English content
- Need multiple distinct character voices
- Budget allows for API costs
PROJECT.md Structure
Minimal Configuration
---
type: project
title: Podcast Title
episodesDir: episodes
audioDir: audio
filePattern: "*.fountain"
exportFormat: m4a
cast:
- character: CHARACTER_NAME
voices:
- apple://voice.id
---
Complete Configuration
---
type: project
title: Full Podcast Title
author: Author Name
description: Detailed podcast description
episodesDir: episodes
audioDir: audio
filePattern: "*.fountain"
exportFormat: m4a
cast:
- character: NARRATOR
voices:
- apple://com.apple.voice.premium.en-US.Aaron # Primary
- apple://com.apple.voice.premium.en-GB.Daniel # Fallback
- character: CHARACTER_TWO
voices:
- elevenlabs://21m00Tcm4TlvDq8ikWAM
---
## Production Notes
[Optional markdown content documenting the project]
Required Fields
type: project- Always requiredtitle- Podcast titleepisodesDir- Relative path to episodes (default:episodes)audioDir- Relative path for output (default:audio)filePattern- Glob pattern for episode files (default:"*.fountain")exportFormat- Audio format:m4a,aiff,wav,caf,mp3cast- Array of character-to-voice mappings
Optional Fields
author- Creator namedescription- Podcast description
Produciesta Generation Commands
Basic Generation
# Generate all episodes
produciesta /path/to/project
# Generate with specific format
produciesta /path/to/project --format m4a
# Verbose output
produciesta /path/to/project --verbose
Single Episode
# By name (relative to episodesDir)
produciesta /path/to/project --episode chapter-01.fountain
# By direct path
produciesta /path/to/project/episodes/chapter-01.fountain
Batch Processing
# Skip existing audio files
produciesta /path/to/project --skip-existing
# Resume from episode N
produciesta /path/to/project --resume-from 50
# Force regenerate all
produciesta /path/to/project --regenerate
Preview Mode
# Dry run (show plan without generating)
produciesta /path/to/project --dry-run
Error Handling
# Stop on first error
produciesta /path/to/project --fail-fast
# Continue on voice resolution errors (use default voice)
produciesta /path/to/project --ignore-generation-errors
Transcript Generation for Web Players
After generating audio, you can deploy .fountain files as transcripts for your podcast website. The web player JavaScript automatically parses and displays them under the audio player.
Transcript Structure
The same .fountain files used for audio generation serve as transcripts:
Example: chapter-01.fountain
---
title: Tao De Jing - Chapter 1
album: Tao De Jing Podcast
artist: Tao De Jing
track: 1
description: Chapter One introduces the fundamental paradox of the Tao.
---
===
Tao De Jing - Chapter 1
[[ slnc 1000 ]]
Chapter One introduces us to the fundamental paradox of the Tao.
[[ slnc 1000 ]]
[[rate 100]]
Speak it aloud, and it slips from your grasp...
[[ rset]]
How Transcripts Are Displayed
The web player JavaScript (in each podcast's index.html):
- Fetches the .fountain file from
episodes/directory - Parses with
parseFountain()function:- Removes YAML frontmatter (
---...---) - Removes section markers (
===) - Strips SSML tags (
[[ slnc 1000 ]],[[rate 100]],[[ rset]]) - Splits into lines
- Removes YAML frontmatter (
- Displays clean text in the transcript section
Result: Only the actual spoken content appears in the transcript.
Preparing Transcripts for Website
Step 1: Copy Fountain Files to Website
# For a podcast at ~/Projects/intrusive-memory.github.com/podcasts/daily-dao/
# Copy all episodes to website episodes directory
cp ~/podcast-project/episodes/*.fountain \
~/Projects/intrusive-memory.github.com/podcasts/daily-dao/episodes/
# Or copy individual episodes
cp ~/podcast-project/episodes/chapter-01.fountain \
~/Projects/intrusive-memory.github.com/podcasts/daily-dao/episodes/
Step 2: Verify Transcript Section in index.html
Ensure the podcast's index.html includes the transcript section:
CSS (in <style> block):
.transcript-section {
background: rgba(0,0,0,0.4);
border-radius: 12px;
padding: 1.5rem;
margin-bottom: 2rem;
max-height: 300px;
overflow-y: auto;
}
.transcript-content {
font-family: 'Roboto', sans-serif;
color: #e2e8f0;
font-size: 1.1rem;
line-height: 1.8;
}
.transcript-line {
padding: 0.5rem 0;
border-bottom: 1px solid rgba(255,255,255,0.05);
}
HTML (before chapters section):
<div class="transcript-section">
<h3>Transcript</h3>
<div class="transcript-content" id="transcript-content">
<p class="transcript-loading">Loading transcript...</p>
</div>
</div>
JavaScript functions:
function parseFountain(text) {
let content = text.replace(/^---[\s\S]*?---\s*/m, '');
content = content.replace(/^===\s*/m, '');
content = content.replace(/\[\[\s*slnc\s+\d+\s*\]\]/gi, '');
content = content.replace(/\[\[\s*rate\s+\d+\s*\]\]/gi, '');
content = content.replace(/\[\[\s*rset\s*\]\]/gi, '');
const lines = content.split('\n')
.map(line => line.trim())
.filter(line => line.length > 0);
return lines;
}
async function loadTranscript(filename) {
const url = '{{ site.baseurl }}/podcasts/podcast-name/episodes/' + filename;
transcriptContent.innerHTML = '<p class="transcript-loading">Loading transcript...</p>';
try {
const response = await fetch(url);
if (!response.ok) throw new Error('Failed to load');
const text = await response.text();
const lines = parseFountain(text);
transcriptContent.innerHTML = lines.map((line, index) => {
return '<div class="transcript-line" data-line="' + index + '">' + line + '</div>';
}).join('');
} catch (error) {
transcriptContent.innerHTML = '<p class="transcript-loading">Transcript not available</p>';
}
}
Call on chapter change:
function playChapter(chapterNum) {
// ... audio loading code ...
loadTranscript('chapter-' + padNumber(chapterNum) + '.fountain');
}
Step 3: Deploy and Test
# Commit to git
cd ~/Projects/intrusive-memory.github.com
git add podcasts/podcast-name/episodes/*.fountain
git add podcasts/podcast-name/index.html
git commit -m "Add transcripts for podcast episodes"
git push
# Test locally (if using Jekyll)
bundle exec jekyll serve
# Visit: http://localhost:4000/podcasts/podcast-name/
Transcript File Naming Conventions
Match the naming pattern used by your audio files:
Daily Dao (numbered chapters):
chapter-01.fountain
chapter-02.fountain
...
chapter-81.fountain
Meditations (Julian day + date):
001_january_01.fountain
002_january_02.fountain
...
365_december_31.fountain
Custom naming (YNTSWYD):
Chapter 1.fountain
Chapter 2.fountain
Epilogue.fountain
Critical: The filename must match what the JavaScript loadTranscript() function constructs.
Workflow Integration
When generating audio with this skill:
- Generate audio with Produciesta
- Copy .fountain files to website
episodes/directory - Verify transcript section exists in
index.html - Test locally that transcripts load correctly
- Deploy to production
Complete Workflow Reference
For the full end-to-end workflow including:
- Audio generation
- Git LFS commit and CDN verification
- Transcript deployment
- RSS feed updates
- Validation and testing
- Production deployment
See: "Complete End-to-End Publishing Workflow" section above.
That section provides a step-by-step walkthrough with all commands, validation steps, and troubleshooting guidance.
Troubleshooting Transcripts
Transcript shows "Transcript not available":
- Verify .fountain file exists in
episodes/directory - Check filename matches what JavaScript constructs
- Inspect browser console for 404 errors
- Verify file permissions (should be readable)
Transcript shows SSML tags like [[ slnc 1000 ]]:
- Update
parseFountain()function to strip all SSML tags - See reference implementation in Daily Dao or Meditations
Transcript shows YAML frontmatter:
- Verify regex in
parseFountain()correctly removes frontmatter - Pattern should be:
/^---[\s\S]*?---\s*/m
Lines are concatenated (not separated):
- Check that
split('\n')is being used - Verify lines are wrapped in
<div class="transcript-line">tags
Troubleshooting
Error: "Character not found in cast list"
Cause: Fountain file contains a character not in PROJECT.md cast section.
Solution 1: Add character to PROJECT.md
cast:
- character: MISSING_CHARACTER
voices:
- apple://com.apple.voice.premium.en-US.Aaron
Solution 2: Use default voice
produciesta /path/to/project \
--default-voice "apple://com.apple.voice.premium.en-US.Aaron"
Solution 3: Re-analyze with Claude Ask Claude to re-read Fountain files and update PROJECT.md cast list.
Error: "Voice provider unavailable"
For ElevenLabs:
# Check API key is set
echo $ELEVENLABS_API_KEY
# Set if missing
export ELEVENLABS_API_KEY="your-key-here"
For Apple TTS:
- Premium voices require download: System Settings → Accessibility → Spoken Content
- Voice ID must be exact (case-sensitive)
Error: "No episodes found"
Check file pattern:
# List files
ls episodes/*.fountain
# Update filePattern in PROJECT.md if needed
filePattern: "*.fountain" # or "chapter-*.fountain", etc.
Audio Quality Issues
Voice too fast/slow:
- Apple TTS: No direct speed control
- ElevenLabs: Has stability/similarity controls
Wrong voice:
- Update voice URI in PROJECT.md
- Regenerate:
produciesta /path/to/project --regenerate
Advanced: Hooks for Automation (macOS Only)
Produciesta supports pre/post-generation hooks for automation:
Create Hooks
mkdir -p /path/to/project/.produciesta-hooks
# Pre-generation hook
cat > /path/to/project/.produciesta-hooks/pre-generation.sh << 'EOF'
#!/bin/bash
echo "🎙️ Starting audio generation at $(date)"
# Validation, setup, notifications
EOF
# Post-generation hook
cat > /path/to/project/.produciesta-hooks/post-generation.sh << 'EOF'
#!/bin/bash
echo "✅ Completed audio generation at $(date)"
# Upload to R2, update RSS feed, deploy to website
EOF
chmod +x /path/to/project/.produciesta-hooks/*.sh
Disable Hooks
produciesta /path/to/project --skip-hooks
Creating Execution Plans
When the user asks to "create an audio plan", generate a planning document:
Plan Template
# Audio Generation Plan: [Project Title]
## Project Overview
- **Location**: /path/to/project
- **Episodes**: [N] .fountain files
- **Characters**: [N] unique characters
- **Format**: M4A
- **Provider**: Apple TTS / ElevenLabs
## Step 1: Character Analysis
[Claude analyzes Fountain files]
Characters identified:
- NARRATOR: 150 lines, authoritative narrator voice
- ALICE: 45 lines, young female protagonist
- BOB: 32 lines, supporting male character
## Step 2: Voice Assignment
[Claude matches voices]
Recommended casting:
- NARRATOR → Aaron (mature, clear, authoritative)
- ALICE → Ava (young female, expressive)
- BOB → Daniel (British accent, professional)
## Step 3: PROJECT.md Creation
[Claude creates/updates PROJECT.md with cast list]
## Step 4: Audio Generation
```bash
cd /path/to/project
produciesta . --format m4a --verbose
Step 5: Quality Check
- Listen to first episode
- Verify voice assignments appropriate
- Check audio quality
- Validate file sizes
Timeline Estimate
- Character analysis: 5 minutes
- Voice matching: 5 minutes
- PROJECT.md creation: 2 minutes
- Audio generation: ~2 minutes per episode
- Quality check: 10 minutes
- Total: [Estimated based on episode count]
## Best Practices
1. **Always analyze all episodes** before assigning voices (characters may appear later)
2. **Document casting rationale** in PROJECT.md production notes
3. **Test with one episode first** before batch processing
4. **Use premium voices for primary characters** (more dialogue = more important)
5. **Consider voice distinctiveness** to avoid confusion between characters
6. **Commit PROJECT.md to git** for version control and team collaboration
7. **Use dry-run mode** to validate configuration before generating
## Related Tools and Resources
- **Produciesta CLI**: `~/Projects/Produciesta/produciesta-cli/`
- **ProduciestaCore**: Audio generation engine
- **Apple TTS**: Built-in macOS voices
- **ElevenLabs**: Premium voice synthesis API
- **Fountain Format**: https://fountain.io/
- **ElevenLabs Voice Library**: https://elevenlabs.io/voice-library
## Quick Reference: Common Commands
### Audio Generation
```bash
# Generate all episodes
produciesta /path/to/project --format m4a --verbose
# Generate single episode
produciesta /path/to/project --episode chapter-01.fountain
# Dry run (preview without generating)
produciesta /path/to/project --dry-run
# Skip existing files
produciesta /path/to/project --skip-existing
Git LFS Management
# Configure LFS for audio files
git lfs track "*.m4a"
echo "*.m4a filter=lfs diff=lfs merge=lfs -text" >> .gitattributes
# Check LFS status
git lfs ls-files
git lfs status
# Verify file is in LFS (not regular git)
git lfs ls-files | grep chapter-01.m4a
CDN Verification
# Test audio availability on CDN
curl -I https://pub-8e049ed02be340cbb18f921765fd24f3.r2.dev/podcast-slug/chapter-01.m4a
# Should return: HTTP/2 200
Transcript Deployment
# Copy transcripts from source to website
cp ~/podcast-source/episodes/*.fountain \
~/Projects/intrusive-memory.github.com/podcasts/podcast-slug/episodes/
# Verify copy
ls -la ~/Projects/intrusive-memory.github.com/podcasts/podcast-slug/episodes/
Get Audio Metadata
# File size (bytes) for RSS feed
stat -f%z audio/chapter-01.m4a
# Duration (seconds) for RSS feed
afinfo audio/chapter-01.m4a | grep "estimated duration"
# Or use ffprobe
ffprobe -v quiet -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 audio/chapter-01.m4a
Jekyll Testing
cd ~/Projects/intrusive-memory.github.com
# Start local server
bundle exec jekyll serve
# Visit: http://localhost:4000/podcasts/podcast-slug/
# Stop server: Ctrl+C
RSS Feed Validation
# Validate feed locally
curl http://localhost:4000/podcasts/podcast-slug/feed.xml | xmllint --format -
# Or use online validator:
# https://validator.w3.org/feed/
Pre-Flight Validation Checklist
Before starting audio generation:
Source Repository:
- Produciesta CLI installed and working:
produciesta --version - All .fountain files present in
episodes/ - PROJECT.md exists with cast list
- Git LFS configured:
git lfs version -
.gitattributeshas*.m4aLFS tracking
Website Repository:
- Podcast page exists at
podcasts/<slug>/ -
index.htmlhas transcript section (CSS, HTML, JavaScript) -
feed.xmltemplate ready -
_data/podcasts.ymlhas podcast entry
Environment:
- Jekyll works:
bundle exec jekyll serve - Git authentication configured
- CDN URL known
Post-Deployment Validation Checklist
After pushing to production:
Production Site:
- Page loads:
https://intrusive-memory.productions/podcasts/<slug>/ - Audio plays from CDN (check Network tab in browser DevTools)
- Transcripts load and display correctly
- Chapter/episode switching works
- Subscribe links are correct
- RSS feed accessible:
https://intrusive-memory.productions/podcasts/<slug>/feed.xml
RSS Feed:
- Feed validates: https://validator.w3.org/feed/
- All episodes have
<enclosure>tags with CDN URLs - File sizes match actual audio file sizes
- Durations are accurate (in seconds)
- Pub dates are valid RFC-822 format
- Test subscribe in podcast app (Apple Podcasts, Overcast, etc.)
GitHub:
- GitHub Pages build succeeded
- No build errors in Actions tab
- LFS files uploaded successfully
Common Troubleshooting
Issue: Audio generation fails with "Character not found"
Cause: Fountain file has character not in PROJECT.md cast.
Solution:
# Re-analyze fountain files
grep "^[A-Z][A-Z ]*$" episodes/*.fountain | sort -u
# Add missing characters to PROJECT.md cast section
Issue: CDN returns 404 for audio files
Cause: LFS files not synced to CDN yet.
Solutions:
- Wait 5-10 minutes for sync
- Verify LFS upload:
git lfs ls-files - Check file is actually in LFS:
git lfs ls-files | grep filename - Verify CDN URL path matches podcast slug
Issue: Transcripts show "Transcript not available"
Cause: .fountain files not copied to website or filename mismatch.
Solutions:
- Verify files copied:
ls podcasts/<slug>/episodes/*.fountain - Check browser console for 404 errors
- Verify filename matches JavaScript
loadTranscript()call - Check file permissions:
chmod 644 episodes/*.fountain
Issue: RSS feed validation fails
Common errors and fixes:
- Invalid date format: Use RFC-822 format:
Wed, 12 Feb 2025 00:00:00 -0500 - Invalid enclosure URL: Must be full CDN URL with https://
- Missing duration: Add
<itunes:duration>285</itunes:duration>(in seconds) - Invalid file size: Get actual size with
stat -f%z audio/file.m4a
Issue: Jekyll build fails
Common causes:
- YAML syntax error in frontmatter
- Invalid HTML in index.html
- Missing required files (favicon, artwork)
Debug:
bundle exec jekyll build --verbose
# Read error message carefully
# Fix syntax errors in indicated files
Issue: GitHub Pages not updating
Solutions:
- Check build status:
gh run list --limit 1 - View build logs in Actions tab
- Hard refresh browser: Cmd+Shift+R (macOS) or Ctrl+Shift+R (Windows)
- Clear browser cache
- Wait 2-3 minutes for CDN cache invalidation
Notes
- Do NOT use
--autocastflag - it's currently not working - Claude-assisted casting provides better control and understanding
- Always verify voice URIs are correct format before generation
- Produciesta handles all audio generation - Claude only creates cast list
- Error logs saved to
GENERATION_ERRORS.mdin project root - Audio files are in Git LFS - not regular git blobs
- CDN serves audio - website only references CDN URLs
- Transcripts are .fountain files - copied from source repo to website
- RSS feeds must be manually updated - no auto-generation yet