skills/youtube-search/SKILL.md
Search YouTube by keyword and return structured video metadata (title, URL, channel, views, duration, date) via yt-dlp. No API keys. Triggers on: "search youtube", "find youtube videos", "top youtube videos on", "trending videos on", "youtube results for", "yt search", "/yt-search".
npx skillsauth add mathews-tom/armory youtube-searchInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Search YouTube by keyword and return structured video metadata — title, URL,
channel, views, duration, upload date. Uses yt-dlp for scraping with no API
keys or OAuth required.
uv tool install yt-dlp
Verify:
yt-dlp --version
yt-dlp "ytsearch10:claude code skills" --dump-json --flat-playlist --no-warnings 2>/dev/null \
| jq -r '[.title, .url, .channel, .view_count, .duration_string, .upload_date] | @tsv'
ytsearch10: — search YouTube, return 10 results (adjust number as needed)--dump-json — output metadata as JSON--flat-playlist — don't download, just list--no-warnings — suppress non-error outputyt-dlp "ytsearch5:claude code mcp servers" \
--dump-json --flat-playlist --no-warnings 2>/dev/null \
| jq '{
title: .title,
url: .url,
channel: .channel,
views: .view_count,
duration: .duration_string,
upload_date: .upload_date,
description: (.description // "" | .[0:200])
}'
yt-dlp does not support server-side sort. To sort by views or date, capture all results and sort client-side:
# Sort by view count (descending)
yt-dlp "ytsearch20:AI agents 2026" \
--dump-json --flat-playlist --no-warnings 2>/dev/null \
| jq -s 'sort_by(-.view_count) | .[:10][] | {title, url, channel, views: .view_count}'
# Sort by upload date (newest first)
yt-dlp "ytsearch20:claude code tutorial" \
--dump-json --flat-playlist --no-warnings 2>/dev/null \
| jq -s 'sort_by(-.upload_date) | .[:10][] | {title, url, channel, upload_date}'
The number after ytsearch controls how many results to fetch:
| Pattern | Results |
| ------------------ | -------------------------------------- |
| ytsearch5:query | 5 results |
| ytsearch10:query | 10 results (default recommendation) |
| ytsearch20:query | 20 results |
| ytsearch50:query | 50 results (slow, may hit rate limits) |
Recommendation: Fetch 15-20 results, then filter/sort client-side to the top N the user wants. This provides enough data for meaningful sorting without being excessive.
User provides search query
|
v
+---------------------+
| Step 0: Deps check |
+----------+----------+
v
+---------------------+
| Step 1: Search |
| (yt-dlp ytsearch) |
+----------+----------+
v
+---------------------+
| Step 2: Parse JSON |
| (jq formatting) |
+----------+----------+
v
+---------------------+
| Step 3: Present |
| results to user |
+---------------------+
yt-dlp "ytsearch${COUNT}:${QUERY}" \
--dump-json --flat-playlist --no-warnings 2>/dev/null
Extract relevant fields with jq. The full metadata object from yt-dlp contains
many fields; the useful subset for search results:
| Field | Description |
| ------------------ | ------------------------------------------ |
| .title | Video title |
| .url | Full YouTube URL |
| .channel | Channel name |
| .view_count | Total views (integer) |
| .duration_string | Duration as H:MM:SS or MM:SS |
| .upload_date | Upload date as YYYYMMDD |
| .description | Video description (can be long — truncate) |
| .like_count | Likes (may be null) |
| .comment_count | Comments (may be null) |
Format as a markdown table for the user:
yt-dlp "ytsearch10:${QUERY}" \
--dump-json --flat-playlist --no-warnings 2>/dev/null \
| jq -s 'sort_by(-.view_count) | .[] | "| \(.title[:60]) | \(.channel) | \(.view_count) | \(.duration_string) | \(.upload_date) |"' -r
Prefix with a header row:
| Title | Channel | Views | Duration | Date |
|-------|---------|-------|----------|------|
# Only videos longer than 10 minutes (600 seconds)
yt-dlp "ytsearch20:deep dive AI agents" \
--dump-json --flat-playlist --no-warnings 2>/dev/null \
| jq -s '[.[] | select(.duration >= 600)] | sort_by(-.view_count) | .[:10][]'
# Only videos from the last 30 days
CUTOFF=$(date -v-30d +%Y%m%d 2>/dev/null || date -d "30 days ago" +%Y%m%d)
yt-dlp "ytsearch20:claude code" \
--dump-json --flat-playlist --no-warnings 2>/dev/null \
| jq -s --arg cutoff "$CUTOFF" '[.[] | select(.upload_date >= $cutoff)] | sort_by(-.view_count) | .[]'
# Search within a specific channel
yt-dlp "ytsearch10:skills site:youtube.com/c/ChannelName" \
--dump-json --flat-playlist --no-warnings 2>/dev/null
Or use the channel URL directly:
yt-dlp "https://www.youtube.com/@ChannelName/search?query=skills" \
--dump-json --flat-playlist --no-warnings 2>/dev/null
# Get just URLs for feeding into other tools (youtube-analysis, notebooklm)
yt-dlp "ytsearch10:claude code MCP" \
--dump-json --flat-playlist --no-warnings 2>/dev/null \
| jq -r '.url'
This skill produces URLs and metadata that feed into other skills:
notebooklm source add "URL"Example pipeline (manual steps, not automated):
/yt-search — discover 10 relevant videosnotebooklm source add or youtube-analysis| Error | Cause | Resolution |
| --------------------------- | ---------------------------------- | ---------------------------------------- |
| No results | Query too specific or misspelled | Broaden the search terms |
| Empty JSON | yt-dlp rate limited by YouTube | Wait a few minutes, retry |
| yt-dlp: command not found | Not installed | uv tool install yt-dlp |
| Partial results | Some videos geo-blocked or private | Normal behavior; results are best-effort |
| Timeout | Network or YouTube slowness | Reduce result count or retry |
.like_count, .comment_count) may be null for certain videos. Always handle nulls in jq filters.testing
Manages dependent branch stacks and stacked pull requests using safe Git topology rules. Triggers on: "create stacked PRs", "publish this stack", "sync my PR stack", "rebase this stack", "merge the stack", "retarget child PRs", "split this branch into stacked PRs", "validate this stack", "cleanup stacked branches". Use when local branches or one source branch need to become a dependency-ordered PR stack with correct parent bases, validation, synchronization, merge order, and cleanup.
development
Scaffolds per-repository agent context so coding agents share the same issue tracker rules, triage label vocabulary, domain glossary, ADR layout, and handoff conventions. Triggers on: "set up project context", "configure agent docs", "create CONTEXT.md", "setup agent workflow", "agent issue tracker setup", "triage labels", "domain glossary for agents". Use when a repo needs durable context files before planning, triage, debugging, TDD, architecture review, or multi-agent implementation.
testing
Produces phased task boards from feature requests: dependency-mapped work items, parallelization flags, risk flags, edge cases, test matrices. Triggers on: "decompose this feature", "task breakdown with dependencies", "phased implementation plan", "work breakdown structure". NOT for effort estimates, use estimate-calibrator.
development
Hypothesis-driven debugging with ranked hypotheses, git bisect strategy, instrumentation planning, and minimal reproduction design. Triggers on: "debug this systematically", "root cause analysis", "bisect this bug", "rank hypotheses", "isolate this issue", "minimal reproduction". NOT for general reasoning.