watch-video
Use this skill when a user asks you to analyze a video URL, local video, screen recording, tutorial, demo, UI bug recording, product walkthrough, or any task where visible UI/actions and spoken content matter.
Locating The Scripts
Every command below runs a script under this skill's scripts/ directory,
which sits next to this SKILL.md. Resolve that skill directory and run scripts
relative to it; do not rely on a client-specific environment variable.
Supported platforms are macOS and Linux.
Operating Rules
- Ask the user which detail level to run for each new video (see "Ask The Detail Level First"); skip the question only when the request or environment already answers it.
- Prefer native captions/transcripts when available. For URLs the script probes captions first and skips the media download when usable captions cover transcript detail and no cue timestamps are pinned.
- Use
yt-dlpfor URL metadata, captions, and media;ffmpeg/ffprobefor audio clips and frames. - Use Groq Whisper as the default fallback when captions are missing or obviously incomplete. Audio beyond the 24 MiB safety threshold, which is below providers' 25 MB upload limit, is chunked and stitched automatically; partial chunk failures degrade to a partial transcript instead of failing the run.
- Use OpenAI transcription only when explicitly requested with
--transcriber openai. - Default Groq model:
whisper-large-v3-turbo. Default OpenAI model:whisper-1(verbose JSON segment timestamps are needed). - Support focused ranges with
--startand--end; use--durationwhen the user gives a start plus length. Finite URL ranges download only that section. - Do not paste the full transcript unless the user explicitly asks for it.
- Do not print or expose
GROQ_API_KEYorOPENAI_API_KEY. - For videos longer than 10 minutes, ask for or infer a focused range before frame-heavy extraction.
- For videos longer than 30 seconds, review captions/transcript before expanding frame extraction.
- For screen recordings or UI text, prefer PNG frames at higher resolution:
--frame-format png --resolution 1024. - If a follow-up question asks about evidence already captured, answer from the frames and transcript in context. Run a focused second pass only when the new question needs visual evidence that was not captured.
- Run artifacts (downloaded media and frames) accumulate outside the plugin
under
$WATCH_VIDEO_RUNS_DIRwhen set, otherwise under$XDG_STATE_HOME/watch-video/runs/or~/.local/state/watch-video/runs/. Once follow-ups are done, use--cleanupto remove media and audio, add--cleanup-framesto remove frames, or delete the run directory to remove every artifact. Keep media when a--from-runsecond pass is likely.
Detail Dial
--detail trades token cost against visual fidelity:
transcript- no sampled frames unless--timestampspins cue frames; with usable captions and no pinned cue timestamps, URLs skip media. If captions are missing or weak, URLs download only audio for Whisper.efficient- keyframe-first decode with uniform fallback when fewer than four keyframes are available, cap 50 frames. Best default for "what is this video about".balanced- scene-change detection with uniform fallback for static footage, cap 80. Use when visuals actually matter.full- detected scene-change coverage, cap 300. For long, important videos where broader visual coverage is worth the context cost.
Every sampled-frame engine drops near-duplicate candidates (held slides, static
screens) before spending the frame cap and reports how many were dropped.
Pinned transcript-cue frames are not deduplicated. Pass --no-dedup only when
near-duplicate sampled candidates are useful; engine selection and frame caps
still apply.
Ask The Detail Level First
Before running the script on a new video, ask the user which detail level to
use through the host's normal user-input mechanism. Present the four levels
lightest to heaviest so the order
itself reads as the cost dial, keep the recommendation label on balanced
even though it is not first, and include the cost hints:
transcript- fastest, lowest cost; no sampled frames, and URLs with usable captions skip media when no cue timestamps are pinned.efficient- keyframe-first skim with uniform fallback; up to 50 frames, low cost.balanced(Recommended) - scene-aware frames; up to 80, moderate cost.full- detected scene changes; up to 300 frames, high context cost.
Skip the question and just run when:
- the user already named a level or passed
--detail; - the request clearly implies one ("just summarize what they say" ->
transcript; "I need every frame" ->full); WATCH_VIDEO_DETAILis set - treat it as the user's standing answer;- you are re-running the same video for a follow-up or a focused second pass - reuse the earlier choice;
- nobody can answer (non-interactive or autonomous run) - use
balancedand say so when you report back.
For videos longer than 10 minutes, fold the focused-range question into the same prompt instead of asking twice.
Whisper Key Setup (Ask Once)
A key is needed only when a video has no usable captions and transcription matters. When that happens and no key is available (environment or stored), ask the user once through the host's normal user-input mechanism with three options:
- Groq key (Recommended - cheaper and faster; https://console.groq.com/keys)
- OpenAI key (https://platform.openai.com/api-keys)
- Skip transcription for this video (captions/frames only)
If they provide a key, store it once for subsequent runs of this skill on the same machine and user profile:
python3 scripts/doctor.py --set-key groq # reads the key from stdin
The key defaults to ~/.config/watch-video/.env with mode 600;
WATCH_VIDEO_CONFIG_DIR overrides the configuration directory, and environment
variables still take precedence over the stored value. Never echo the key back,
never commit it, and confirm only the safe shape (Groq keys start with gsk_,
OpenAI keys with sk-). If the user skips, run with --transcriber none and
only raise the question again when a later video actually needs transcription.
Invocation
From this skill directory:
python3 scripts/watch.py "<source>"
Useful patterns:
python3 scripts/doctor.py
python3 scripts/watch.py "<source>" --detail transcript
python3 scripts/watch.py "<source>" --detail efficient
python3 scripts/watch.py "<source>" --start 01:15 --end 02:00
python3 scripts/watch.py "<source>" --duration 30 --max-frames 8
python3 scripts/watch.py "<source>" --mode tutorial
python3 scripts/watch.py "<source>" --mode ui-bug --frame-format png --resolution 1024
python3 scripts/watch.py "<source>" --transcriber none
CLI option surface:
--detail transcript|efficient|balanced|full--transcriber groq|openai|none--mode general|tutorial|ui-bug|notes(report scaffold)--timestamps T1,T2,...to pin frames at exact moments--from-run DIRto reuse a prior run's usable media; runs without media and focused URL downloads are rejected--start/--end/--durationfor focused ranges--max-frames Ncap override (hard caps: 100, or 300 in full detail)--resolution(alias--frame-width), default 512--frame-format jpeg|png|webp--sub-langsyt-dlp caption selector (default English variants)--no-dedup,--no-frames;--frame-mode intervalwith--frame-interval, or--fps(uniform-sampling overrides)--out-dir DIRfor a custom run-artifact base;WATCH_VIDEO_RUNS_DIRorXDG_STATE_HOMEcan set the default base--cleanupremoves media and audio; add--cleanup-framesto remove frames
The script writes a run directory outside the plugin under
$WATCH_VIDEO_RUNS_DIR, $XDG_STATE_HOME/watch-video/runs/, or the fallback
~/.local/state/watch-video/runs/, then prints the final report.md. Quote
URLs in zsh and other shells where ? may be treated as a glob.
Transcript-Cue Frames
Scene detection can miss the moment a presenter points at something, because "look here" is often a low visual change. Catch those with a two-pass flow:
- Run once and read
transcript.md.--detail transcriptis the lowest-cost choice, but a URL with usable captions run at that level without pinned cue timestamps retains no media. - Scan for deictic cues - "look here", "as you can see", "watch this", "notice" - and judge which ones matter. That judgment is yours, not a regex.
- If the earlier run retained full, untrimmed media, re-run with
--timestamps 4:32,7:10 --from-run <previous-run-dir>using absolute source times. Otherwise rerun the original source with--timestamps 4:32,7:10and omit--from-run.
Cue frames use the frame cap before sampled frames, bypass deduplication, and
are labeled transcript-cue in the report. If requested cues exceed the cap,
an evenly spaced subset is kept. With --detail transcript --timestamps ...,
the selected cue frames are the only frames.
Token Efficiency
Frame count and pixel dimensions increase context cost, but exact image-token
accounting depends on the host and model. At the same aspect ratio, a
1024px-wide frame contains roughly four times as many pixels as a 512px-wide
frame. Raise resolution only when on-screen text must be read. Prefer
transcript or efficient detail for skims, a focused --start/--end range
over a sparse full-video scan, and avoid rerunning for evidence already in
context.
Evidence To Use
Inspect report.md first. If frames were extracted, inspect every frame image
before answering visual questions, in parallel when the host supports it;
frames are chronological and timestamped in the filename. Use
transcript.md for spoken content, but summarize and cite timestamp ranges
rather than dumping the full transcript.
Response Shape
Unless the user asks for a narrower format, return:
- Summary
- Timeline with timestamps
- Visible UI/actions
- Commands/tools mentioned
- Implementation steps or reproduction steps
- Uncertainty and what would improve confidence
For UI bug videos, include the observed symptom, timestamped evidence, likely cause, and next debugging checks. For tutorials, extract the commands, tools, setup steps, decisions, and a compact implementation checklist.
Failure Handling
- First run: use
python3 scripts/doctor.pyfor dependency and safe key-shape checks. - Missing
yt-dlp,ffmpeg, orffprobe: runpython3 scripts/doctor.py --install. It uses Homebrew when available on macOS; otherwise it prints manual commands. On Linux it prints commands but never executessudo. Other operating systems are reported as unsupported. - Missing Whisper key when transcription is needed: run the ask-once flow in "Whisper Key Setup"; if the user declines, continue with captions/frames and note that transcription was skipped.
- Groq API failure: do not retry indefinitely; report the error category and use available captions/frames. On chunked audio, partial results are kept.
- No captions on a non-English video: pass
--sub-langsfor that language (for example"es,es.*") or rely on the Whisper fallback. - Subtitle failures are isolated from the later media download because media fetches never request subtitles; a complete metadata/caption probe failure can still stop the run.
- Login-required, private, or region-locked URL: say
yt-dlpcannot fetch it without access and ask for a local file or accessible URL.
Security And Data Flow
yt-dlpcommunicates with the source host to fetch metadata, captions, and media. Downloaded media, frames, transcripts, and reports remain under the local run directory.- When captions are missing or weak and hosted Whisper fallback is enabled, the
extracted audio clip is uploaded to the selected provider. Groq keys go only
to
api.groq.com; OpenAI keys go only toapi.openai.com. - Stored keys default to
~/.config/watch-video/.envwith mode 600 and can be relocated withWATCH_VIDEO_CONFIG_DIR. They are written only bydoctor.py --set-keyfrom stdin; environment variables take precedence. - Never print keys or place run artifacts inside a repository. Default run storage is outside the plugin package.