yt-dlp
CLI skill for
yt-dlp: read-only URL probes, caption/transcript extraction, and optional media download. Follow the
transcript-first protocol before any download.
Scope: Supported video/audio hosts via
, user-owned cookie files, playlist metadata, and local output under an explicit directory.
NOT for: static page fetch (use Fetch MCP or
), broad multi-source research (
), ffmpeg transform recipes (
), or bypassing platform Terms of Service.
Canonical Vocabulary
| Term | Meaning | NOT |
|---|
| probe | Read-only metadata via ; no media write | download |
| transcript | Captions/subtitles to text files; prefer over full download | audio rip by default |
| download | Persist media bytes after probe + user approval | silent bulk grab |
| playlist | Multi-entry URL; enumerate before selective download | blind full-playlist download |
| cookies | User-owned Netscape cookie file passed with | committed or skill-bundled secrets |
| doctor | Preflight JSON report for binary, version, ffmpeg | live URL smoke |
| format id | yt-dlp from probe (e.g. , ) | guessed extension |
| manual sub | Creator-uploaded captions | auto-generated only |
| auto sub | Platform-generated captions | guaranteed accuracy |
Dispatch
| Mode | Action |
|---|
| / / | Probe | Run bundled ; summarize title, id, duration, subs |
| / / | Transcript | Probe first; extract best available subtitles without video download |
| / / | Download | Probe first; confirm rights + format; download to explicit output dir |
| Playlist | Probe with playlist allowed; list entries; selective download only with approval |
| / | Cookies | Validate user-owned cookie file path; never copy into repo |
| / | Doctor | Run scripts/doctor.py --format json
|
| Natural language: "what is this video", "get subtitles", "download this" | Auto | Map to probe → transcript → download per protocol below |
| (empty) | Help | Show modes, protocol, ethics pointer, and examples |
Auto-Detection Heuristic
- URL + words like subtitle, caption, transcript, CC → Transcript (still probe first).
- URL + download, save, mp4, audio, rip → Download (still probe + approval first).
- URL + playlist, channel list, all videos → Playlist.
- Bare URL or "what is this link" → Probe.
- Path ending in or mention of login/auth → Cookies guidance, then re-probe with .
- Ambiguous → ask: metadata only, transcript, or download?
Transcript-First Protocol
Run these stages in order. Do not skip probe. Do not download until transcript needs are ruled out or the user explicitly wants media files.
Stage 1 — Doctor (once per session or after errors)
bash
uv run python scripts/doctor.py --format json
Stop on
or any check with
(missing
binary).
Stage 2 — Probe (mandatory before transcript or download)
bash
uv run python scripts/probe_url.py --url 'https://…' --format json
With user-owned cookies:
bash
uv run python scripts/probe_url.py --url 'https://…' --cookies "$HOME/.config/yt-dlp/cookies.txt" --format json
Playlist URL (enumerate entries; pass
on probe):
bash
uv run python scripts/probe_url.py --url 'https://www.youtube.com/playlist?list=PL…' --allow-playlist --format json
From probe JSON, report:
,
,
,
,
,
/
languages, and recommended
candidates. Load
references/formats-and-quality.md when choosing formats.
Stage 3 — Transcript (preferred over download)
When subtitles exist, extract text without downloading video:
bash
yt-dlp --skip-download --write-subs --write-auto-subs --sub-langs 'en.*,en' \
--convert-subs srt --sub-format srt \
-o '%(title).200B.%(ext)s' \
--paths home:"$HOME/Downloads/yt-dlp/transcripts" \
'URL'
Prefer
manual subs over
auto when both exist. Summarize path to
/
and offer to strip timing lines for plain text. If no subs: say so and ask before download-for-transcription (higher cost, rights-sensitive).
Stage 4 — Download (explicit approval required)
Before running:
- Confirm the user has rights to save the content (personal/archive/fair-use context per references/ethics-and-tos.md).
- Confirm output directory (default:
$HOME/Downloads/yt-dlp/media/
).
- Confirm format from probe ( or sensible default: ).
bash
mkdir -p "$HOME/Downloads/yt-dlp/media"
yt-dlp -f 'bv*+ba/b' \
--paths home:"$HOME/Downloads/yt-dlp/media" \
-o '%(playlist_index)s-%(title).200B.%(ext)s' \
'URL'
Report output path, format id, file size, and whether ffmpeg merge ran.
Mode Details
Probe mode
- Use bundled (wraps
yt-dlp --dump-json --no-download
).
- Read-only: no writes under cwd or repo.
- For age-gated or login-only content, stop and route to Cookies — do not guess credentials.
Transcript
- Never default to downloading video/audio for text needs.
- Use always.
- If multiple languages, pick user-requested lang or with fallback list from probe.
Download
- Single URL default: unless user asked for playlist.
- No bulk channel/archival without explicit scope confirmation.
- Do not embed cookies in commands in chat logs; reference env or user path only.
Playlist
- Probe with playlist enabled:
bash
uv run python scripts/probe_url.py --url 'PLAYLIST_URL' --allow-playlist --format json
- Present numbered entries (index, title, duration).
- Download selected indices only () after approval — never blind full playlist.
Cookies
- User-owned cookie file only — path under user home or explicit user-provided path.
- Never commit cookie files, never store in repo, never bundle in skill package.
- Export guidance (browser extension → Netscape ) lives in references/ethics-and-tos.md.
- Validate readability:
bash
test -r "$HOME/.config/yt-dlp/cookies.txt" && echo readable
Pass
only on probe/download when user supplied the path.
Doctor
bash
uv run python scripts/doctor.py --format json
Parses JSON
,
, and per-check
. Stop workflow on
. Treat
(e.g. missing ffmpeg) as advisory.
Help
Show dispatch table, transcript-first protocol, default paths, and ethics reference link.
Gallery (Empty Arguments)
Present common invocations when
is empty:
| # | Task | Example |
|---|
| 1 | Preflight | |
| 2 | Probe metadata | /yt-dlp probe https://www.youtube.com/watch?v=…
|
| 3 | Get subtitles | /yt-dlp transcript https://www.youtube.com/watch?v=…
|
| 4 | Download (after approval) | /yt-dlp download https://www.youtube.com/watch?v=…
|
| 5 | Playlist enumerate | /yt-dlp playlist https://www.youtube.com/playlist?list=…
|
| 6 | User-owned cookies | /yt-dlp cookies ~/.config/yt-dlp/cookies.txt
|
Pick a number, a mode from the dispatch table, or paste a URL and say whether you need metadata, subtitles, or a download.
Critical Rules
- Probe before transcript or download — always use or equivalent
--dump-json --no-download
.
- Transcript before download — prefer subtitle extraction when captions exist.
- Explicit approval for downloads — confirm rights, scope, output dir, and format.
- User-owned cookies only — never commit, copy into repo, or invent cookie paths.
- No ToS bypass coaching — see references/ethics-and-tos.md; refuse DRM circumvention or paywall evasion requests.
- Not Fetch MCP — static HTML, docs pages, and non-yt-dlp hosts → Fetch MCP or , not this skill.
- Not ffmpeg skill — remux, transcode, clip, waveform → after download if needed.
- Least privilege output — write only under user-approved directories, never into the agents repo tree.
- Report provenance — title, URL, extractor, format id, and output paths in the final summary.
Troubleshooting
See references/troubleshooting.md for extractor errors, geo blocks, signature failures, and ffmpeg merge issues.
References
| File | Use when |
|---|
| ethics-and-tos.md | Rights, cookies, refusal boundaries |
| formats-and-quality.md | Choosing format strings |
| troubleshooting.md | Errors after doctor passes |
Scripts
| Script | Purpose |
|---|
| JSON preflight: yt-dlp, version, ffmpeg |
| Read-only wrapper |
| Validate skill manifest and evals |
Examples
bash
# Preflight
uv run python scripts/doctor.py --format json
# Probe
uv run python scripts/probe_url.py --url 'https://www.youtube.com/watch?v=dQw4w9WgXcQ' --format json
# Transcript (after probe shows subs)
yt-dlp --skip-download --write-subs --write-auto-subs --sub-langs en -o '%(id)s' \
--paths home:"$HOME/Downloads/yt-dlp/transcripts" 'URL'
# Download (after user approval)
yt-dlp -f 'bv*+ba/b' --paths home:"$HOME/Downloads/yt-dlp/media" -o '%(title).200B.%(ext)s' 'URL'