Gnomad Harvester — YouTube Transcripts for Zero Dollars
How I pull YouTube captions locally with yt-dlp and youtube-transcript-api — no YouTube Data API, no Google Cloud — and hand the text to agents.
- youtube
- transcripts
- yt-dlp
- local-first
- agents

I kept pasting YouTube links and hoping
If you run a studio with agents, a YouTube URL is not a source. It is a pointer. The model did not watch the video. I wanted a list of talks in, transcripts out, then a skill or a review — without a Google Cloud invoice.
That tool already existed in the workspace. We just had not put it on the site. Gnomad Harvester pulls captions on this machine. Default path costs nothing.
What Gnomad Harvester actually does
Captions first, not OCR. Most videos already have a timed-text track.
- Resolve a playlist (a single watch URL often works as a one-item list) with
yt-dlp --flat-playlist - Try
youtube-transcript-apiagainst YouTube’s public caption endpoint - If that fails,
yt-dlp --write-auto-subs --skip-download— still local, still free - Write plain-text transcripts, optional Ollama three-bullet summaries, and markdown for agents
No YouTube Data API v3. No Places. No Maps. No billed GCP product in the loop.
There is an optional third-party API (youtube-transcript.io) if YouTube blocks your IP. That is paid credits and not Google. I leave it off.
| Path | Cost |
|---|---|
| Captions + yt-dlp | nothing |
| Local Ollama summary | nothing (your GPU) |
| youtube-transcript.io | paid, optional |
| YouTube Data API / GCP | not used |
I have already used this on real work: a CSS units talk became a client-site skill, and a Hermes memory tutorial became a fleet review instead of a cargo-cult install.
Recreate it, then list it
The CLI lives in our ORGANIZATION tree. It is not a public GitHub repo yet. The recipe is public so you can rebuild it in an afternoon.
- Product card: davidcole.cloud/apps/gnomad-harvester
- Recreate docs: davidcole.cloud/projects/gnomad-harvester
Minimum viable clone: install yt-dlp, pip install youtube-transcript-api, fetch one video_id, fall back to --write-auto-subs if the API returns nothing. Wrap that in a loop over a playlist dump. Optional: POST the transcript to local Ollama for three factual bullets.
For a single talk I still skip the playlist CLI and run:
yt-dlp --skip-download --write-auto-subs --sub-langs "en,en-US,en-orig" \
-o "./%(id)s" "https://www.youtube.com/watch?v=VIDEO_ID"
That file is what I hand the agent. OCR and Whisper stay off the default path — they are for videos with no captions at all.
AI-assisted, human-verified: this post was drafted against the Inkwell brief (tools, cost table, public URLs) and checked against the actual Python fallback order in gnomad_harvester.
What I’d do differently
I would have put Gnomad Harvester on the homepage showcase the week we wrote it. Maps mentioned “yt-summarizer.” The files agents read first did not. Next step: a --url flag for a single video so nobody has to pretend a watch link is a playlist — then, if we publish source, keep the README’s first line: captions are free; cloud APIs are not the default.