Skip to content
WINSTON FOWLKES

Jacksonville, Florida.
Working wherever good projects happen.

winston@winstonf.com

Otis Jiry Autonomous audio production

One narrator. Agents run everything between the microphone and the feed.

How a horror podcast runs on a phone recording room, a serverless audio pipeline, and Claude Code agents that edit, score, master, illustrate, and release each episode, with a human voice at the center.

Otis Jiry's Midnight Transmission website hero: an older narrator with a white beard at a vintage microphone in a dark radio room, beside the red Midnight Transmission title
The public site at otisjiry.com. Every episode is narrated by Otis; the production around him is software and agents.View full size
Voice
Human, recorded on a phone
Episodes
3 released, Season 1
Release
Unattended agent run

The premise

Keep the performance human. Automate the rest.

Otis Jiry is an established horror narrator with a following that knows his voice. Midnight Transmission is his show: independent horror fiction, free to listen, supported by listeners. The part people come for is the voice, so that part stays human. Otis reads every word himself, on his own phone, from home.

Everything around that performance is the problem this project solves. A narrated episode normally needs a studio, an editor, a mixing engineer, a composer, a designer, a video editor, and someone to push the release out to every platform. Here those jobs are done by a recording room built into the website, a serverless audio pipeline, and Claude Code agents working from a written production procedure. I direct and approve by ear.

The show went from first commit on February 27, 2026 to three released episodes by September 20. Apple Podcasts listed it on September 15. The third episode was published by an agent on a timer with nobody watching.

Who does what.

The voice

Otis performs

Otis narrates every story and records his own spoken intros. When the post-production agent finds a missing line, the fix is a pickup request to Otis, not a synthetic patch. There is no voice clone anywhere in the system.

The direction

I direct and approve

I pick covers from three candidates, set release dates, and sign off on each master by listening to the open, a key scene, and the final three minutes. My ear caught splice clicks, a score that did not fit, and a dropped word, and each of those became a rebuild and a new rule in the procedure.

The agents

Agents do the work between

Transcript audits, click repair, cleanup, loudness, scoring, assembly, scene art, captioned video, teasers, publishing, the Facebook launch post, web push, and feed verification are run by Claude Code sessions following the show's release procedure.

The software

The app keeps the take safe

The recording room handles capture, punch-ins, autosave, chunked uploads, and server-side joining, so a dropped connection or a closed tab never costs Otis a performance.

The Transmissions section of otisjiry.com with three episode cards: Long Time Dead, The Breathing Room, and Last Watch, each with cover art and runtime
The three released episodes on the public site. Two are submissions from outside writers, credited by name; the third is a Midnight Transmission original.View full size

The recording room: a studio in a phone browser.

Otis records at record.otisjiry.com, a private part of the same Next.js app. He opens a signed invite link once, and the room remembers him for six months. The script, the recorder, and every safety net sit on one screen.

  1. Raw capture, no phone processing

    The microphone opens with echo cancellation, noise suppression, and automatic gain all switched off, mono, so the phone does not pump or smear the voice. The browser recorder writes Opus in WebM at 128 kbps, falling back to MP4 on iPhone. A microphone picker remembers his choice and shows a red warning for Bluetooth headsets, which cap around 8 kHz and sound like a phone call. A ten-second mic test with a live level meter runs before a session.

  2. Punch and roll

    Mistakes are fixed the way a studio engineer would do it. Otis scrubs a waveform to the spot, arms the punch point, and hears five seconds of his own lead-in before recording starts on its own. The take is cut at that sample and the new audio is appended. Otis asked for the pre-roll; an earlier version that started recording immediately was reverted.

  3. The script follows his voice

    After a punch, twelve seconds of lead-in are downsampled to 16 kHz and transcribed, then matched against the last eighteen words of the script with an anchored word-level edit distance and a 0.72 confidence floor. The page scrolls to his place and highlights what to read next. Ambiguous repeated passages are refused rather than guessed, and a manual word search is always there.

  4. Undo that survives a reload

    Before any punch that replaces audio, the untrimmed take is kept in memory and written to the phone's IndexedDB. If more than twenty seconds would be cut, the full pre-punch take is also uploaded to the server in the background.

  5. Autosave on two layers

    Every thirty seconds the recorder is cycled, the take is merged into a WAV, and a copy is written to IndexedDB, with a guard so a late autosave can never overwrite a newer take. Every 115 seconds at most, a full snapshot goes to the server. Recovery offers the server take, the latest snapshot, the phone copy, or the pre-punch copy, each labelled with its length.

  6. Uploads that fit a phone

    Uploads go straight from the browser to a private Supabase Storage bucket through signed URLs, which avoids the web host's request size limit. Anything over 32 MB is split in the browser into WAV parts of about two minutes and at most 12 MB, each with a rewritten header, using blob slices so a memory-limited phone never holds a second copy. Each part retries three times and a retry resumes from the last finished part.

  7. Joined on the server, verified first

    A serverless function downloads the parts, checks every WAV header, sample rate, and channel count, and confirms the byte total matches what the phone reported before it writes anything. FFmpeg then concatenates the parts into a 48 kHz mono MP3, stepping the bitrate down for very long reads. If the bytes do not add up, the save fails loudly instead of keeping a partial take.

  8. Takes never overwrite each other

    Every save becomes its own take. A pickup that is less than half the length of the longest take, and more than a minute shorter, is filed as a short take and cannot replace the full read. Otis can switch the active take himself. Spoken intros are recorded separately, and the chosen intro is joined to the story with half a second of silence, keyed by a hash of both files so it can never be prepended twice.

Post-production: the chain an agent runs on every episode.

The shipped episodes were mastered outside the app by Claude Code sessions working from the show's release procedure, on my workstation or on an always-on server. Each step writes its settings and measurements to a working folder so the next session can check it.

Post-production: the chain an agent runs on every episode.
StageWhat the agent doesSettings and checks
Pull the takeDownloads the active take and converts it for editing48 kHz mono WAV
Gap auditTranscribes the take with phrase timings and diffs it against the script to find missing or misread linesTranscribed in 4-minute chunks with anchored offsets, because one long pass drifted minutes late by the 15-minute mark. Word match on the last two stories: 97.7% and 98.5%
PickupsA missing line becomes a request to Otis. The new audio is spliced at a detected silence and loudness-matchedsilencedetect boundary, acrossfade, EBU R128 match
Click repairScans for punch-in joins that click and repairs each oneA sample jump above 0.15 of full scale and more than 5 times the local 99.5th-percentile slope. Loud plosives never pass 0.12. Each join gets a 6 ms fade out and in, then the scan repeats until it finds zero
CleanupRemoves rumble, hiss, and sibilance and evens out the readhighpass 80 Hz, light afftdn only if hiss is audible, de-esser, 2.5:1 compression, loudnorm to -16 LUFS, -1.5 dBTP, LRA 11
EditsCuts false starts and stray laughsShort fragments are confirmed with loudness and spectral envelopes rather than a model's opinion
ScoreWrites a timed instrumental bed that follows the storyTen cues of 78 to 150 seconds per episode, placed at story offsets with 2 s fade in and 3 s fade out, shaped by a long piecewise gain curve
AssemblyBuilds the episode: show open, Otis's intro, sting, story, outroThe music ducks under the voice with sidechain compression at 3:1, 60 ms attack, 900 ms release. The outro drop lands 0.15 s before Otis's last spoken word, found by silence detection on the final 30 seconds
MasterLimits, encodes, tags, and embeds the coverlimiter at 0.95, MP3 128 kbps, 48 kHz mono, title, artist, album, and cover tags

Scoring

A composer that works to a timeline.

The first episode's bed was made with ElevenLabs Music. Its composition plans sing any text they are given, so the agent learned to leave the text fields empty and describe each cue through style alone. Two cues were crossfaded and shaped by a gain envelope timed to the story.

The second and third episodes moved to Google's Lyria 3.5 when a 23-minute score would have needed about 36,000 music credits. Each cue costs about eight cents and 25 seconds to render. The agent writes ten timed prompts with section markers, places each cue at its story offset, and draws a gain curve across the whole episode. The target is a bed around -34 LUFS under a -16 LUFS voice, so it is felt more than heard.

The process has a real editor's feedback loop. On The Breathing Room I said the score did not fit, and the cues were regenerated with percussion, pulse, and heartbeat banned from the prompts. The first version is kept next to the second.

The released masters.

Measured from the final files with ffprobe and an EBU R128 loudness scan.

The released masters.
EpisodeRuntimeFormatLoudnessScore
S1E1 Last Watch11:34MP3 192 kbps, 48 kHz monoMastered to -16 LUFS targetElevenLabs Music, two cues
S1E2 Long Time Dead23:41MP3 128 kbps, 48 kHz mono, cover embedded-16.0 LUFSLyria 3.5, ten cues
S1E3 The Breathing Room22:59MP3 128 kbps, 48 kHz mono, cover embedded-16.2 LUFSLyria 3.5, ten cues, second version

From a master to a video and teasers, unattended.

  1. Scene art

    An agent writes a beat list from the transcript and generates a square image per beat. A batch of 25 runs for about 45 minutes with nobody at the desk.

  2. Slideshow

    Slow Ken Burns moves are rendered supersampled: images scaled 4x, motion rendered at 2x, then downscaled, which removes the jitter FFmpeg's zoom filter normally shows.

  3. Captions

    Word timings from the cleaned audio drive burned-in captions in the show's serif typeface, with an end card for the website. A smaller web copy is encoded for fast start.

  4. Teasers

    10 to 25 second cuts at the scariest line, square and vertical, normalized to -16 LUFS, with a one-second cover hold so social platforms pick the cover as the thumbnail.

Distribution.

  1. The feed

    The RSS feed carries the iTunes and Podcasting 2.0 namespaces, season and episode numbers, durations, and artwork. Each enclosure length is read from the real storage object. If any released episode's size cannot be read, the feed returns an error instead of quietly dropping the episode, because a silently missing episode is worse than a visible failure.

  2. The platforms

    The show is live on Apple Podcasts and Spotify, and on YouTube as captioned video. Apple artwork only rendered once the image URL carried a file extension, so the feed rewrites it to one.

  3. Web push

    Listeners who opt in get a push notification the moment an episode goes live. Dead subscriptions are pruned automatically.

  4. Facebook

    Launch posts go out from the terminal through the Meta Graph API with a guard that refuses to post unless the target Page matches exactly, since one token can reach several clients' Pages. The pattern is a link-free post with the cover or teaser, then a first comment with the website, Apple, and Spotify links.

  5. The website

    otisjiry.com hosts every episode with its own page, player, and listen tracking, plus a tip jar and a public form for writers to submit stories.

What the ear taught the pipeline

Trust the waveform. Keep a person on the final listen.

Model listen-checks could not hear splice clicks. The fix was a numeric detector on the waveform, and the procedure now says so in plain words. The same went for short fragments: loudness and spectral envelopes proved more reliable than asking a model whether a sound was a laugh.

Heavy cleanup made Otis sound processed. A blind A/B chose the lighter noise reduction, and a popular one-click enhancer is only a fallback because it flattens his low end. His voice is the product, so the chain is built to stay out of its way.

Every problem I caught by ear became a written rule the next agent session follows. That is the real system here: a narrator, a procedure that learns, and agents that run it without being walked through it.

By the numbers.

From the repository and the live services as of September 23, 2026.

By the numbers.
MeasureValue
Build windowFebruary 27 to September 2026
Commits90
Application codeAbout 25,000 lines, plus 2,300 lines of production scripts
Pages and route handlers26 pages, 72 route handlers
Database tables19
Automated tests83 tests and 11 browser scenarios at the September 17 release
Episodes released3, from September 13 to September 20
Per-episode productionAudio post 3 to 5 hours of agent time, art and video in parallel, publish 30 minutes

For your business

Keep the human part human.

If your work has one thing only a person can do, we can build the pipeline that handles everything around it.

Services behind this work

Continue exploring

  • Slotica

    From a game idea to the parts that make it playable.

  • Brandeezy

    Give the next image the context of the whole brand.