watch-video
Skill873 starsChanged 25 days agoMITView on GitHub
When you want to extract content from a video — YouTube, Loom, Vimeo, Riverside, Zoom recording, local MP4, X/IG video, anything yt-dlp supports. Three depth modes user picks per invocation — transcript (just words, fast/free), visual (transcript + ffmpeg frame extraction + Claude vision pass on key moments), multimodal (Gemini native video ingestion if $GEMINI_API_KEY set, else dense Claude vision). Uses local Whisper for transcription (MLX-Whisper on Apple Silicon, faster-whisper elsewhere), falls back to platform-provided transcripts when available (Loom, Riverside, YouTube auto-subs). Saves to ~/Documents/videos/<source>-<slug>-<date>/ and optionally captures summary to second-brain raw/ as call-/meeting-/note-. Triggers on "/watch-video <url>," "watch this video," "transcribe this loom," "analyze this video," "summarize this recording," "key moments from this," "what happened in this video." For a post's text and engagement, use social-fetch.
- Reads credentials
- Installs packages
- Sends data out
We split this skill into the rules it gives an agent
9 rules. 0 are common, 6 are distinctive, and 3 are very specific to this project.
0
Common
Most of the 11 edited versions we read keep these.
6
Distinctive
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 34
If the depth isn't specified and the video is >10 minutes, ask before defaulting (visual/multimodal cost real money on long videos).
- Distinctive: line 68
Platform-provided transcript: if it exists and looks complete:
- Distinctive: line 72
If platform transcript exists and has timestamps, use it.
- Very specific: line 166
After moments are identified, synthesize the whole video into <workdir>/summary.md:
- Very specific: line 200
Gemini native: if $GEMINI_API_KEY is set (much cheaper + faster than per-frame for long videos):
- Distinctive: line 233
Dense Claude vision fallback: if no Gemini key:
- Distinctive: line 254
After any mode completes, offer:
- Distinctive: line 277
If captured to second-brain: that path too
- Very specific: line 319
Scene-change detection catches slide transitions: When the video is a slide presentation, add ffmpeg -vf "select='gt(scene,0.3)'" to force …
“Common” is measured: kept by at least 6 in 10 of the 11 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
/watch-video — Transcribe and analyze any video at the depth you choose
Replaces and broadens the prior youtube-transcript skill. YouTube is now one of many sources; depth is user-controlled.
Step 1 — Parse input
Accept:
- YouTube: full URL,
youtu.be/<id>,youtube.com/shorts/<id>, raw 11-char ID - Loom:
loom.com/share/<id>orloom.com/embed/<id> - Vimeo:
vimeo.com/<id> - Riverside: download URL or local file
- Zoom: local
.mp4from a downloaded recording - X / IG / TikTok video: URL — defers to
social-fetchfor metadata, uses yt-dlp for the file - Local file: any path to an
.mp4/.mov/.webm/.mkv
Detect source from URL pattern or file extension. If ambiguous, ask.
Step 2 — Parse depth mode
| Invocation | Mode | What you get |
/watch-video <url> | transcript (default) | Clean text, metadata, optional chapters |
/watch-video <url> transcript | transcript | Same as default |
/watch-video <url> visual | visual | Transcript + frames at intervals + Claude vision pass identifying key moments |
/watch-video <url> multimodal | multimodal | Native video to Gemini (if $GEMINI_API_KEY), else dense Claude vision frame-by-frame |
If the depth isn't specified and the video is >10 minutes, ask before defaulting (visual/multimodal cost real money on long videos).
Step 3 — Pull metadata
For URL sources, use yt-dlp:
yt-dlp --print "%(title)s|%(uploader)s|%(duration_string)s|%(upload_date>%Y-%m-%d)s|%(description)s" \
--print "%(chapters)j" --skip-download "<url>"Capture: title, uploader/channel, duration, upload date, description (first paragraph), chapters (JSON or null).
For local files, use ffprobe:
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "<file>"Step 4 — Build workdir
~/Documents/videos/<source>-<slug>-<date>/Where:
source:youtube/loom/vimeo/riverside/zoom/localslug: kebab-case of title (first 4–6 words, max 50 chars)date:YYYY-MM-DD
Step 5 — Get the transcript
Backend selection (in order):
- Platform-provided transcript if it exists and looks complete:
- YouTube:
yt-dlp --write-sub --write-auto-sub --skip-download --sub-lang en --sub-format vtt - Loom: fetch via
https://www.loom.com/share/<id>page metadata or Loom API if$LOOM_API_KEYset - Riverside: built-in transcripts available on the recording's share page
- If platform transcript exists and has timestamps, use it. Skip Whisper.
- YouTube:
- MLX-Whisper local (default on Apple Silicon Macs):
Or via the CLI:# Install once: pip install mlx-whisper python3 -c "import mlx_whisper; mlx_whisper.transcribe('<file>', path_or_hf_repo='mlx-community/whisper-large-v3-turbo')" \ > "<workdir>/transcript-raw.json"mlx_whisper <file> --model mlx-community/whisper-large-v3-turbo --output-dir <workdir> - Not on Apple Silicon (Linux, Intel Mac, Windows, cloud agents):
faster-whisper(pip install faster-whisper, CPU or CUDA) orwhisper.cpp. Same model size, same output handling.
Download the video file first if it's a URL (use yt-dlp; Loom/Vimeo/YT all supported):
yt-dlp -f "bv*[height<=720]+ba/b[height<=720]" -o "<workdir>/video.%(ext)s" "<url>"720p is plenty for transcription and frame analysis (smaller download, faster processing).
Clean the transcript (only needed for YouTube auto-subs which have rolling captions; Whisper output is already clean):
# YouTube VTT cleanup — de-dup rolling captions, strip tags, paragraph-break on cue gaps >2s
awk '
/^WEBVTT/ || /^Kind:/ || /^Language:/ || /^NOTE/ { next }
/-->/ { in_cue = 1; last = ""; next }
/^$/ { if (last) print last; in_cue = 0; last = ""; next }
in_cue { gsub(/<[^>]+>/, "", $0); last = $0 }
END { if (last) print last }
' "<workdir>/transcript.en.vtt" | awk '!seen[$0]++' > "<workdir>/transcript.txt"Save final to <workdir>/transcript.txt.
Step 6 — If transcript mode: stop here
Output:
transcript.txtmetadata.json- One-line summary in chat: title, source, duration, word count
- Path to workdir
- (Optional) Step 9 — offer to capture to second-brain
Step 7 — If visual mode: extract frames + vision pass
Frame extraction (ffmpeg)
Cadence by source heuristic:
| Source type | Frame cadence |
| Screen-share / Loom / demo | 1 frame per 5s (UI changes fast) |
| Talking head / podcast | 1 frame per 30s (slow change) |
| Slide presentation | 1 frame per 10s + force a frame on each detected scene change |
| Default if unsure | 1 frame per 15s |
mkdir -p "<workdir>/frames"
ffmpeg -i "<workdir>/video.mp4" -vf "fps=1/15" "<workdir>/frames/frame-%04d.png" -yFor scene-change detection (slide decks especially):
ffmpeg -i "<workdir>/video.mp4" -vf "select='gt(scene,0.3)',showinfo" -vsync vfr "<workdir>/frames/scene-%04d.png" 2> "<workdir>/scene-detection.log"Vision pass
Pair each frame with the transcript chunk for the same timestamp window. Then batch-send to Claude vision for synthesis.
Per-frame batch prompt (up to ~10 frames per call):
Here are N frames from a video at timestamps T1..TN. For each frame, describe what's on screen in 1–2 sentences. Flag: (a) UI changes from previous frame, (b) text visible on screen, (c) any moment that looks like a decision, action, or notable event. Also note the transcript text spoken during this window.
Save the output as <workdir>/moments.md:
# Key moments — <title>
## 00:00:15 (frame-001.png)
**On screen**: Login form, email field focused
**Transcript**: "So you just open it up and..."
**Note**: Beginning of UI demo
## 00:00:45 (frame-002.png)
**On screen**: Dashboard with 4 cards
**Transcript**: "And here's where you see all your projects."
**Note**: Major view change — first time the dashboard appearsGenerate summary
After moments are identified, synthesize the whole video into <workdir>/summary.md:
# Summary — <title>
**Source:** <source URL / file>
**Duration:** <hh:mm:ss>
**Watched at:** <date>
**Mode:** visual
## TL;DR
<2–4 sentences>
## Key moments
- 00:00:15 — <one-line>
- 00:00:45 — <one-line>
## Action items flagged
- <item> [timestamp]
## Decisions flagged
- <decision> [timestamp] — consider routing to /decide
## Quotes worth keeping
- "..." [timestamp]
## Open questions
- <question raised but not answered>Step 8 — If multimodal mode
Backend selection
Gemini native if
$GEMINI_API_KEYis set (much cheaper + faster than per-frame for long videos):Default model:
gemini-3.5-flash(released May 2026, ~$1.50 input / $9 output per 1M tokens; ~$0.15/sec of video; beats 3.1 Pro on coding/agentic benchmarks at 4× the speed). Override togemini-3.1-profor brand audits / high-stakes analysis where details matter;gemini-2.5-flash-litefor bulk cheap processing.# Step 1: Upload video via Files API FILE_URI=$(curl -s -X POST "https://generativelanguage.googleapis.com/upload/v1beta/files?key=$GEMINI_API_KEY" \ -H "X-Goog-Upload-Command: start, upload, finalize" \ -H "Content-Type: video/mp4" \ --data-binary "@<workdir>/video.mp4" | jq -r '.file.uri') # Wait until file is ACTIVE (Gemini processes the video first) while true; do STATE=$(curl -s "$FILE_URI?key=$GEMINI_API_KEY" | jq -r '.state') [ "$STATE" = "ACTIVE" ] && break sleep 3 done # Step 2: Generate content with the file + multimodal-analysis prompt curl -s -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.5-flash:generateContent?key=$GEMINI_API_KEY" \ -H "Content-Type: application/json" \ -d "{ \"contents\":[{ \"parts\":[ {\"file_data\":{\"mime_type\":\"video/mp4\",\"file_uri\":\"$FILE_URI\"}}, {\"text\":\"<multimodal analysis prompt — see Step 7's summary template + use-case extensions>\"} ] }] }"Files persist in Gemini Files API for ~48 hours — useful for re-querying the same video with different prompts.
- Dense Claude vision fallback if no Gemini key:
- Frame cadence: 1 frame per 3s (much denser than visual mode)
- Batch through Claude vision with the multimodal-analysis prompt
- Slower and more expensive than Gemini for long videos — warn the user before running on >10min content
Multimodal output
Same summary.md template as Step 7 + an extended section:
## Multimodal observations
- **Body language / delivery**: <observations on talking-head video>
- **Pacing**: <fast/slow/uneven>
- **Visual style**: <brand audit, ad review, design observations>
- **Audio quality / atmosphere**: <music, silence, background>Exact extra sections depend on the use case (brand audit, ad review, talk delivery review, client-call read). Use case is inferred from the source + the user's verbal framing when invoking.
Step 9 — Optional: capture to second-brain
After any mode completes, offer:
"Want to capture this to second-brain? I'll write a
call-<slug>.md(ormeeting-/note-/resource-) to${SECOND_BRAIN_VAULT:-$HOME/Documents/SecondBrain}/raw/with the summary, source URL, and transcript link."
Type prefix by source:
| Source | Prefix |
| Loom / Zoom / Riverside / Otter / call recording | call- |
| Meeting (own notes, not a transcript) | meeting- |
| Talk / keynote / conference | note- |
| Ad / landing-page video / marketing reference / competitor video | resource- |
File body: 1-line source, the summary, link to full workdir.
Step 10 — Report
In chat:
- One-line headline:
<source> · <title> · <duration> · <mode> · <word count> words - Workdir path
- For
visual/multimodal: brief list of top 3 key moments - For all modes: any action items / decisions flagged for triage
- If captured to second-brain: that path too
Sources reference
| Source | Download | Built-in transcript | Notes |
| YouTube | yt-dlp | Auto-subs (--write-auto-sub) | Same as the prior youtube-transcript skill |
| Loom | yt-dlp (Loom supported) | Yes — fetch via embed metadata or Loom API | Async screenshare focus — prime use case |
| Vimeo | yt-dlp | Sometimes | Marketing/embed videos |
| Riverside | Direct URL from export, or local file | Yes — Riverside generates them | Podcast episodes |
| Zoom | Local .mp4 (downloaded recordings) | Sometimes (Zoom audio transcript file) | Client calls |
| X / IG / TikTok | Defer to social-fetch for metadata, yt-dlp for file | No | Short-form |
| Local file | n/a | n/a | Drop a path |
Composes with
social-fetch— for X/IG/TikTok URL metadata (engagement, author, replies) before video processingsecond-brain— capture summary asraw/call-<slug>.md,meeting-,note-, orresource-per source typedecide— when a video contains a flagged decision, route to/decidefor structured capturepm— action items flagged in summary can be triaged to project boardsslide-deck— talk recordings → outline extraction → deck draft (loop)jab-hook— quotes + clip-worthy moments from podcast/talk videos feed BIP/promo postsskillify from-video— primary use case forvisualmode on process recordings. the user records themselves doing a workflow (Loom/screen-share), this skill extracts transcript + key visual moments, thenskillifysynthesizes the workflow into a SKILL.md. "Record once, AI converts to skill."
Error handling
| Failure | Response |
| Video unavailable / private / region-locked | Report and stop |
| No subtitles + Whisper not installed | Tell the user: pip install mlx-whisper (Apple Silicon) or pip install faster-whisper (anything else) |
| ffmpeg missing (for visual/multimodal) | Tell the user: brew install ffmpeg |
| Vision pass returns empty / unclear | Lower the frame count, retry, or fall back to transcript-only with a note |
Multimodal requested but no $GEMINI_API_KEY and >30min video | Warn cost, offer to fall back to visual mode |
yt-dlp binary missing | brew install yt-dlp |
Notes on quality
- User picks depth, not the skill. Transcript / visual / multimodal are 3 different cost + latency profiles. Long videos (>10 min) always confirm before spending on visual/multimodal.
- Platform transcript first, Whisper second. YouTube auto-subs, Loom transcripts, Riverside built-in transcripts — all free + instant when they exist. Fall back to local Whisper only when nothing platform-provided works.
- Local Whisper is the fast path. MLX on M-series Macs transcribes faster than real-time; faster-whisper is the equivalent elsewhere. Cloud Whisper is a distant second choice — costs money, network dependency, worse latency on typical durations.
- Frame cadence by source type. Screen-share / demos need 1 frame per 5s (UI changes fast); talking-head podcasts need 1 per 30s (slow change). Default 15s if unsure. Wrong cadence = missed key moments OR wasted vision-pass cost.
- 720p is plenty. Downloading 1080p / 4K for transcription + frame analysis wastes bandwidth + storage.
yt-dlp -f "bv*[height<=720]+ba/b[height<=720]"is the default. - Scene-change detection catches slide transitions. When the video is a slide presentation, add
ffmpeg -vf "select='gt(scene,0.3)'"to force a frame on each detected slide change — more reliable than pure time-based sampling. - Multimodal cost warning is non-optional. Gemini multimodal on a 60-min video is meaningfully expensive. Warn before running; offer transcript-only as fallback if the user isn't sure.
- Summary format includes routing hints.
## Decisions flagged+## Action items flaggedsections signal/decideand/pmfollow-ups. Downstream composability lives in the summary structure.
Other versions12 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 12
- The-AIOS/aios★ 93same name
- Newuxtreme/watch-video-skill★ 67same name
- matteotitta/genesys-skills★ 46same name
- mikefilsaime-groove/yt-dlp-superpowers★ 4same name
- Ootto-AI/ootto-watch★ 4same name
- ryankolean/summit-claude-skills★ 3same name
- yanchrisdifa/claude-skill-watch-video★ 3same name
- kimtth/agent-skill-100-lines-or-less★ 2same name
- marwanm7moud/watch-video★ 2same name
- anaidenko/claude-video-digest★ 1same name
2 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository21 other files it gives its agents.
- business-brainstormSkill
- company-brainSkill
- company-cfoSkill
- decideSkill
- deep-researchSkill
- domainSkill
- ingestSkill
- jab-hookSkill
- loopifySkill
- maker-councilSkill
- pasteSkill
- personal-cfoSkill
- pmSkill
- radarSkill
- read-bookSkill
- second-brainSkill
- skillifySkill
- slide-deckSkill
- social-fetchSkill
- toolifySkill
- unstuckSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

