How to Debug Issues with watch.skill Video Processing: A Complete Guide
To debug watch.skill video processing issues, trace the deterministic 10-step pipeline from configuration through frame extraction, checking stderr output and the temporary working directory for intermediate artifacts.
The watch.skill in the bradautomates/claude-video repository is a pure-Python orchestration layer that coordinates yt-dlp, ffmpeg, and optional Whisper API calls to download videos, extract representative frames, and generate transcripts. When processing fails or produces unexpected results, systematic debugging requires understanding how data flows through skills/watch/scripts/ and where each stage reports diagnostic information. This guide covers the exact file locations, function behaviors, and diagnostic flags you need to isolate and resolve video processing errors.
Understanding the watch.skill Processing Pipeline
The pipeline executes deterministically across ten distinct stages, each implemented in specific modules within skills/watch/scripts/ according to the bradautomates/claude-video source code:
-
Configuration Loading –
config.pycallsget_config()(L48-L62) to load user defaults from~/.config/watch/.envor environment variables, determining detail level and frame caps. -
Metadata & Captions – For URL sources,
download.py'sfetch_captions()queriesyt-dlpfor metadata and embedded subtitles, called fromwatch.py(L97-L105). -
Video Download –
download.py'sdownload()(L115-L126) fetches the full video or audio-only streams. -
Metadata Extraction –
frames.py'sget_metadata()(L86-L119) runsffprobeto capture duration, resolution, codec, and audio presence. -
Time-range Handling –
frames.pyusesparse_time()andparse_timestamps()(L55-L74 & L95-L109) to convert--start,--end, and--timestampsarguments into seconds. -
FPS Budgeting –
auto_fps()andauto_fps_focus()inframes.py(L22-L39) calculate frame rates respecting the--max-framescap and focus windows. -
Cue-frame Extraction –
extract_at_timestamps()(L24-L34) inframes.pypulls single frames at specified timestamps (never dropped). -
Detail-engine Extraction – Based on
--detail, it runs one of three engines: -
Deduplication –
dedupe_perceptual()inframes.py(L64-L71) collapses near-identical frames using perceptual thumbnails (DEDUP_THUMB=16). -
Transcription & Reporting –
whisper.pyhandles API transcription when subtitles are missing, andwatch.pygenerates the final Markdown summary (L70-L89), sending all diagnostics to stderr.
Common Failure Points and Solutions
When the watch command fails, match your symptoms to the specific pipeline stage:
-
"ffprobe is not installed" – Occurs during metadata extraction at
frames.py:L86. Verifyffprobeis on your$PATHbefore running the command. -
"subtitle parse failed" – Check the VTT file under
work/download/; the path is printed inwatch.py:L99-L107. -
Zero frames extracted – The engine may have dropped everything due to a very low cap defined in
config.py:L65-L74. Inspect theframes/directory in the working directory to confirm. -
Whisper fallback not triggered – Ensure
~/.config/watch/.envcontainsWATCH_WHISPER_OPENAIorWATCH_WHISPER_GROQ. The script hints to runsetup.pywhen keys are missing (watch.py:L60-L64). -
Unexpected timestamps –
extract_at_timestamps()drops timestamps outside the focus window (frames.py:L48-L52). Check the summary for drop counts (watch.py:L88-L94). -
Slow or crashing extraction – The script uses
-loglevel error. For deeper logs, temporarily change the level inframes.py:L80andframes.py:L118.
Enabling Runtime Diagnostics
Increase visibility into the pipeline using these specific techniques.
Print Internal Variables
Insert debug statements that write to stderr, matching the script's [watch] prefix format:
import sys
print("[debug] fps_budget=", fps_budget, file=sys.stderr)
Force FFmpeg Verbosity
Edit the cmd lists in frames.py within functions like extract(), extract_scene_candidates, extract_keyframes, or extract_at_timestamps. Replace "-loglevel", "error" with "info" or "debug" to see frame-by-frame processing.
Enable Debug Mode
Run with the debug environment variable to preserve intermediate files and verbose output:
WATCH_DEBUG=1 watch https://youtu.be/abcd1234 \
--detail balanced \
--out-dir ./debug-run \
--max-frames 30 \
2> debug.log
Isolating Components for Targeted Debugging
Test individual pipeline stages without running the full orchestration.
Run the Scene Engine Directly
Invoke the frame extraction module independently to see raw FFmpeg stderr:
python -m skills.watch.scripts.frames extract_scene_candidates \
./sample.mp4 ./tmp/scene_frames \
--resolution 512
This dumps showinfo output enumerating detected scene changes with timestamps.
Inspect Working Directories
After execution, watch.py prints the working directory path (L84-L89). List contents to verify intermediate artifacts:
ls -R /path/to/working/dir/
Check for downloaded videos in work/download/ and extracted frames in frames/.
Validate Configuration
Test your environment file parsing:
from skills.watch.scripts.config import get_config
print(get_config())
If the detail value is unexpected, check WATCH_DETAIL environment variables or ~/.config/watch/.env formatting (requires KEY=VALUE without extra spaces).
Force Specific Whisper Backends
Override automatic backend selection to verify API connectivity:
watch my_video.mp4 \
--whisper openai \
--no-dedup \
--out-dir ./whisper-test
The script prints the selected backend (L40-L45). If the API key is missing, the script guides you to run setup.py.
Summary
- The watch.skill pipeline in bradautomates/claude-video follows a deterministic 10-stage flow from configuration to final report generation, implemented across
watch.py,config.py,download.py,frames.py, andwhisper.py. - All diagnostic messages are sent to stderr, and the working directory path is printed at the end of execution for artifact inspection.
- Common issues include missing
ffprobeinstallations, invalid API keys in~/.config/watch/.env, and frame caps set too low inconfig.py. - You can isolate problems by running individual modules like
frames.pydirectly and temporarily increasing FFmpeg's log level fromerrortodebug.
Frequently Asked Questions
Why does watch.skill report "ffprobe is not installed" even though I have FFmpeg?
The script requires ffprobe specifically to be available on your system $PATH for metadata extraction at frames.py:L86. Verify installation by running which ffprobe or ffprobe -version. If installed in a non-standard location, symlink it to /usr/local/bin or add its directory to your PATH before executing the watch command.
How do I prevent the frame extraction engine from dropping frames?
The engine drops frames when your --max-frames cap (defined in config.py:L65-L74 or via CLI) is lower than the calculated sample count. Increase the cap with --max-frames 50 or switch to detail=efficient which uses extract_keyframes() and produces fewer frames. Check the frames/ directory in the working directory to verify what was actually extracted.
Where should I store my Whisper API key for transcription fallback?
Create or edit ~/.config/watch/.env and add either WATCH_WHISPER_OPENAI=sk-xxxxxxxx or WATCH_WHISPER_GROQ=your-groq-key. The script loads these via whisper.py's load_api_key() function. If the key is missing, watch.py directs you to run setup.py to create the configuration file template.
Can I extract frames only at specific timestamps without processing the entire video?
Yes. Use the --timestamps flag with detail=transcript to skip standard frame extraction and only pull cue frames:
watch ./video.mp4 --detail transcript --timestamps "00:10,00:45,01:20"
The extract_at_timestamps() function in frames.py handles these extractions and reports if any timestamps fall outside your specified --start or --end windows.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →