Pre‑flight Checks in setup.py for ffmpeg, yt‑dlp, and API Key Validation
The setup.py script in bradautomates/claude-video runs three mandatory pre‑flight checks: binary availability for ffmpeg, ffprobe, and yt‑dlp; detection of a Whisper API key via _have_api_key(); and an aggregated readiness status in _status() that returns "ready" only when all conditions pass.
This article breaks down the validation logic implemented in skills/watch/scripts/setup.py so you understand exactly what gates must clear before the /watch video‑processing skill can execute.
Binary Availability Check for ffmpeg, ffprobe, and yt‑dlp
The _check_binaries() function validates that three command‑line tools are present on the host system.
It uses shutil.which to probe the PATH for each binary:
ffmpeg— required for video and audio transcodingffprobe— required for media introspectionyt‑dlp— required for YouTube/video downloads
# From skills/watch/scripts/setup.py lines 35-68
def _check_binaries():
required = ["ffmpeg", "ffprobe", "yt-dlp"]
missing = []
for binary in required:
if shutil.which(binary) is None:
missing.append(binary)
return missing
If any binary is missing, it is appended to the missing_binaries list. This list drives subsequent user‑facing error messages and determines whether the installer logic triggers.
API Key Presence Check for Whisper Backends
The second pre‑flight test determines whether a transcription backend is configured. The _have_api_key() function scans the environment (or a generated .env file) for credentials.
| Variable | Backend | Priority |
|---|---|---|
GROQ_API_KEY |
groq | checked first |
OPENAI_API_KEY |
openai | fallback |
# From skills/watch/scripts/setup.py lines 16-21
def _have_api_key():
groq = os.getenv("GROQ_API_KEY")
openai = os.getenv("OPENAI_API_KEY")
if groq:
return (True, "groq")
if openai:
return (True, "openai")
return (False, None)
The function returns a tuple (has_key: bool, backend: str | None). This enables downstream logic to report which provider is active, not merely whether a key exists.
Aggregated Readiness Status in _status()
The _status() function combines binary and key checks into a single structured snapshot. According to the source code, four states are possible:
| State | Condition |
|---|---|
"ready" |
No binaries missing and API key present |
"needs_install" |
Binaries missing, key present |
"needs_key" |
Binaries present, key missing |
"needs_install_and_key" |
Both binaries and key missing |
# Logic derived from skills/watch/scripts/setup.py lines 29-44
def _status():
missing = _check_binaries()
has_key, backend = _have_api_key()
if not missing and has_key:
status = "ready"
elif missing and not has_key:
status = "needs_install_and_key"
elif missing:
status = "needs_install"
else:
status = "needs_key"
can_proceed = (not missing) and (has_key or os.getenv("SETUP_COMPLETE") == "true")
return {
"status": status,
"missing_binaries": missing,
"has_key": has_key,
"backend": backend,
"can_proceed": can_proceed
}
The can_proceed boolean merits attention: it evaluates to True when all binaries exist and the user either (a) has an API key or (b) has previously completed the installer with SETUP_COMPLETE=true persisted. This supports headless re‑runs without re‑authenticating.
Silent and JSON Output Modes
The setup script supports two invocation patterns for CI and programmatic consumption.
Silent check (exits 0 on success, non‑zero on failure):
python3 skills/watch/scripts/setup.py --check
This is the mode used by hooks/scripts/check-setup.sh to gate Git operations.
Machine‑readable JSON status:
python3 skills/watch/scripts/setup.py --json
Example output structure:
{
"status": "needs_install",
"missing_binaries": ["yt-dlp"],
"has_key": true,
"backend": "groq",
"can_proceed": false
}
Common Failure Scenarios and Messages
When checks fail, the script emits actionable guidance:
| Scenario | Output |
|---|---|
| Missing binaries, no key | [watch] setup incomplete (missing binaries: ffmpeg, yt-dlp; no Whisper API key). Run: python3 /path/to/setup.py |
| All checks pass | [setup] ready. whisper backend: groq |
Running the script without arguments launches the interactive installer, which:
- Installs missing binaries via Homebrew on macOS
- Scaffolds a
.envfile for API keys - Writes
SETUP_COMPLETE=trueupon successful key detection
Summary
- Binary validation —
_check_binaries()usesshutil.whichto confirmffmpeg,ffprobe, andyt-dlpare on PATH - API key detection —
_have_api_key()returns(bool, str)tuple indicating presence and backend type - Readiness aggregation —
_status()computes four discrete states and acan_proceedboolean - CLI interface —
--checkfor silent exit codes,--jsonfor structured output - Integration point —
hooks/scripts/check-setup.shinvokes--checkto enforce pre‑conditions before Git push
Frequently Asked Questions
What happens if ffmpeg is installed but ffprobe is not?
The _check_binaries() function treats each binary independently as implemented in skills/watch/scripts/setup.py lines 35-68. Missing ffprobe alone will populate missing_binaries with ["ffprobe"], causing _status() to return "needs_install" and can_proceed: false until that binary is available.
Can I bypass the API key check and still run /watch?
Yes, conditionally. The can_proceed logic evaluates to True if SETUP_COMPLETE=true is set in the environment, even without an API key. This allows re‑runs after initial setup. However, transcription features will fail at runtime if no key is configured when Whisper processing is requested.
How does setup.py distinguish between Groq and OpenAI backends?
The _have_api_key() function checks GROQ_API_KEY first, then OPENAI_API_KEY, returning the matching backend string. This priority order means Groq takes precedence if both variables are set. The backend identifier propagates through _status() to user‑facing messages and JSON output.
Why does --check produce no output on success?
This design supports shell scripting and Git hooks. The cmd_check() wrapper exits with code 0 when _status()["can_proceed"] is True, enabling constructs like python3 setup.py --check || echo "Setup required". Failure cases print diagnostic context to stderr before exiting non‑zero.
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 →