# How setup.py Checks for Dependencies on First Run in Claude Video

> Learn how setup.py verifies dependencies like ffmpeg, yt-dlp, and API keys on first run in the Claude Video repository. Ensure a smooth setup process.

- Repository: [bradautomates/claude-video](https://github.com/bradautomates/claude-video)
- Tags: internals
- Published: 2026-08-07

---

**The [`setup.py`](https://github.com/bradautomates/claude-video/blob/main/setup.py) script performs an idempotent pre-flight check on every `/watch` skill invocation by detecting the `SETUP_COMPLETE` marker in `~/.config/watch/.env`, verifying that `ffmpeg`, `ffprobe`, and `yt-dlp` exist in the system PATH, and checking for a Whisper API key via `GROQ_API_KEY` or `OPENAI_API_KEY` variables.**

The bradautomates/claude-video repository provides a Claude skill for processing video content. When users invoke the `/watch` command for the first time, the system must ensure that external binaries and API keys are available before proceeding. The [`setup.py`](https://github.com/bradautomates/claude-video/blob/main/setup.py) module located at [`skills/watch/scripts/setup.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/setup.py) implements a lightweight, non-destructive dependency verification system that runs automatically to validate the environment without requiring manual intervention.

## The Three-Step Dependency Detection Process

The dependency check follows a strict three-phase logic that aggregates results into a final status. Each phase examines a specific requirement needed for the video processing skill to function.

### Step 1: Detecting First-Run State

The `is_first_run()` function (lines 24-27) determines whether the user has completed initial setup by checking for the marker `SETUP_COMPLETE=true` in `~/.config/watch/.env`. If this marker is absent or not set to `true`, the function returns `True`, indicating that the current invocation represents a first-run scenario. This boolean flag controls whether the system enforces the presence of a Whisper API key.

### Step 2: Verifying Required Binaries

The script validates the presence of three external programs defined in the `REQUIRED_BINARIES` constant (line 35): `ffmpeg`, `ffprobe`, and `yt-dlp`. The helper function `_which()` (lines 62-64) wraps Python's `shutil.which` to locate executables in the system PATH. The core verification logic in `_check_binaries()` (lines 66-68) iterates through the required list and returns a list of any binaries that are not found. This check is operating-system agnostic and works on macOS, Linux, and Windows environments where these tools are installed.

### Step 3: Checking for Whisper API Keys

For transcription capabilities, the skill requires access to either Groq or OpenAI Whisper APIs. The `_have_api_key()` function (lines 16-21) delegates to `_read_env_key()` (lines 92-113) to search for `GROQ_API_KEY` or `OPENAI_API_KEY` in the process environment or the `~/.config/watch/.env` configuration file. The function returns a tuple containing a boolean indicating key presence and a string identifying the backend provider.

## How setup.py Classifies Installation Status

The private `_status()` function (lines 229-255) aggregates the three verification steps into a coherent state dictionary:

```python
missing = _check_binaries()          # List[str] of missing binaries

has_key, backend = _have_api_key()     # (bool, str) for API availability

setup_complete = not is_first_run()  # bool indicating prior setup

```

Based on these values, the system categorizes the environment into one of four status strings:

- **ready**: All binaries present and API key available.
- **needs_install**: Binaries missing but API key present.
- **needs_key**: Binaries present but no API key during first run.
- **needs_install_and_key**: Both binaries and API key missing.

This classification determines whether the `/watch` skill can proceed or must prompt the user for configuration.

## Command-Line Interface and Exit Codes

The `cmd_check()` function (lines 59-92) serves as the `--check` entry point and translates the internal status into actionable exit codes for shell integration and automation:

```bash
python3 -m skills.watch.scripts.setup --check

```

The function returns exit code `0` (silent) when `can_proceed` evaluates to `True`. Non-zero exits indicate specific remediation requirements:

| Exit Code | Condition |
|-----------|-----------|
| `2` | Missing binaries only |
| `3` | First run without Whisper API key |
| `4` | Both binaries and API key missing |

This allows CI/CD pipelines and wrapper scripts to detect configuration issues programmatically without parsing human-readable output.

## Running the First-Time Installer

When invoked without arguments, `cmd_install()` triggers the full installation workflow. On macOS, the script attempts automatic installation of missing binaries via Homebrew through `_install_macos()`. The installer also calls `_scaffold_env()` to create an empty `~/.config/watch/.env` file if it does not exist, providing placeholders for API keys. Once a key is detected, `_write_setup_complete()` persists `SETUP_COMPLETE=true` to the configuration file, disabling future first-run checks.

To simulate a fresh installation for testing purposes:

```bash
rm -f ~/.config/watch/.env
python3 -m skills.watch.scripts.setup --check

# Exits with code 3, indicating first-run state without API key

```

For human-readable debugging output including the full status dictionary:

```bash
python3 -m skills.watch.scripts.setup --json

```

## Summary

- **First-run detection** relies on the `SETUP_COMPLETE=true` marker in `~/.config/watch/.env`, checked by `is_first_run()` (lines 24-27).
- **Binary verification** confirms the presence of `ffmpeg`, `ffprobe`, and `yt-dlp` using `_check_binaries()` (lines 66-68) and the `REQUIRED_BINARIES` constant (line 35).
- **API key validation** searches for `GROQ_API_KEY` or `OPENAI_API_KEY` via `_have_api_key()` (lines 16-21) and `_read_env_key()` (lines 92-113).
- **Status aggregation** occurs in `_status()` (lines 229-255), producing four distinct states: `ready`, `needs_install`, `needs_key`, and `needs_install_and_key`.
- **Exit codes** `2`, `3`, and `4` from `cmd_check()` (lines 59-92) signal specific missing dependencies, while `0` indicates full readiness.

## Frequently Asked Questions

### What happens if I run setup.py without the SETUP_COMPLETE flag?

If the `SETUP_COMPLETE` marker is missing from `~/.config/watch/.env`, `is_first_run()` returns `True`, causing the system to require a Whisper API key before proceeding. The script will exit with code `3` (if binaries are present) or code `4` (if both binaries and keys are missing), prompting you to configure `GROQ_API_KEY` or `OPENAI_API_KEY`.

### How does setup.py detect missing binaries across different operating systems?

The script uses `_which()` (lines 62-64), which wraps Python's `shutil.which` to search the system PATH environment variable. This approach is cross-platform and works identically on macOS, Linux, and Windows, returning the absolute path to executables or `None` if they are not found in the PATH.

### Can I use the /watch skill without a Whisper API key?

No, the skill requires either a Groq or OpenAI API key for transcription functionality. During the first run (when `SETUP_COMPLETE` is not set), the absence of `GROQ_API_KEY` or `OPENAI_API_KEY` causes `cmd_check()` to exit with code `3`, preventing the skill from processing video content until you add the credentials to your environment or `~/.config/watch/.env` file.

### How do I reset the first-run state to reconfigure the skill?

Delete the configuration file at `~/.config/watch/.env` or remove the `SETUP_COMPLETE=true` line within it. This causes `is_first_run()` to return `True` on the next invocation, triggering the full dependency check and allowing you to reconfigure binaries and API keys by running `python3 -m skills.watch.scripts.setup` without arguments.