# Video Tool

> Video processing toolkit. Use when user wants to: - Download videos from YouTube or other sites - Remove silence from videos - Trim, cut, or extract segments from videos - Extract audio from video files - Enhance or denoise audio - Replace audio track in a video - Change video playback speed - Concatenate multiple videos - Generate transcripts/captions (VTT) - Generate video descriptions, timestamps, or context cards - Upload videos to YouTube or Bunny.net CDN - Post social updates to X (Twitter) or LinkedIn - Get video metadata (duration, resolution, codec)

- Skill: `alejandro-ao/video-tool` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add alejandro-ao/video-tool`
- Raw SKILL.md: https://api.skillmd.com/api/skills/alejandro-ao/video-tool/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: alejandro-ao (https://skillmd.com/u/alejandro-ao)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/alejandro-ao/video-tool

---


# Video Tool CLI

AI-powered video processing toolkit with ffmpeg operations, local or remote Parakeet/Whisper transcription, and content generation.

## Installation Status

video-tool: !`which video-tool > /dev/null && echo "INSTALLED" || echo "NOT INSTALLED - run installation below"`
uv: !`which uv > /dev/null && echo "INSTALLED" || echo "NOT INSTALLED"`

If video-tool is not installed, run the installation commands below before proceeding.

## Installation

```bash
# Install uv first (if not installed)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install video-tool
uv tool install git+https://github.com/alejandro-ao/video-tool-cli.git
```

### Dependencies
- **ffmpeg**: Required for all video operations (`brew install ffmpeg` on macOS)
- **yt-dlp**: Required for video downloads (`brew install yt-dlp` on macOS)
- Local transcription runtimes are optional; install the platform-specific extra described under **Transcription & Timestamps**

### API Keys Setup

Configure API keys (choose one method):

**Option 1: Non-interactive (recommended for Claude Code)**
```bash
video-tool config keys --set groq_api_key=YOUR_KEY
video-tool config keys --set openai_api_key=YOUR_KEY
# Multiple at once:
video-tool config keys --set groq_api_key=xxx --set openai_api_key=yyy
```

**Option 2: Edit credentials file directly**
If users prefer not to share keys with Claude Code, they can edit directly:
```bash
# File: ~/.config/video-tool/credentials.yaml
openai_api_key: sk-xxx
groq_api_key: gsk_xxx
bunny_library_id: xxx
bunny_access_key: xxx
replicate_api_token: xxx
```

**Option 3: Interactive setup**
```bash
video-tool config keys
```

Required keys:
- **openai_api_key** - CLI content generation (descriptions, context cards, transcript-based timestamps)

Optional keys:
- **groq_api_key** - Remote Groq Whisper transcription; not needed for local models
- **bunny_library_id**, **bunny_access_key** - Bunny.net CDN uploads
- **replicate_api_token** - Audio enhancement

```bash
video-tool config keys --show   # View configured keys (masked)
video-tool config keys --reset  # Clear all credentials
```

## IMPORTANT: Handling Authentication Errors

**When a command fails with "AUTHENTICATION REQUIRED" or "API key not configured":**

1. **DO NOT** try to work around the issue by writing custom scripts
2. **DO NOT** try to call APIs directly
3. **INSTEAD**, offer the user two options using AskUserQuestion:

**Option A: Provide key to Claude (convenient)**
- User gives you the API key directly
- You run: `video-tool config keys --set KEY_NAME=VALUE`
- Faster, but the key is visible in the conversation

**Option B: User configures privately (more secure)**
- User runs the command themselves or edits the file directly
- Key never appears in the conversation with Claude
- Tell user to run: `video-tool config keys` (interactive)
- Or edit: `~/.config/video-tool/credentials.yaml`

**Example AskUserQuestion prompt:**
"This command requires a [Groq/OpenAI] API key. How would you like to configure it?"
- Option 1: "I'll provide the key" - convenient but key visible to Claude
- Option 2: "I'll configure it myself" - more private, key stays hidden from Claude

After user configures (either way), retry the original command.

**Commands that require credentials:**
- `video-tool generate transcript -m groq/whisper-large-v3-turbo` → Requires **Groq API key**
- Local transcription models → Require no API key, but their optional runtime must be installed
- `video-tool video timestamps -m transcript` → Requires **OpenAI API key** (structured output)
- `video-tool upload bunny-*` → Requires **Bunny.net credentials**
- `video-tool video enhance-audio` → Requires **Replicate API token**
- `video-tool upload x` / `video-tool upload twitter` → Requires **X OAuth credentials** (run `video-tool config x-auth`)
- `video-tool upload linkedin` → Requires **LinkedIn access token + author URN** (run `video-tool config keys` or pass flags)

---

## Content Generation: CLI Commands vs Direct Generation

Some CLI commands use OpenAI to generate content. When Claude runs this skill, it's often better for Claude to generate content directly instead of calling another LLM.

### Use CLI command (requires OpenAI API key):
- `video timestamps -m transcript` - Uses structured output for precise JSON

### Generate directly as Claude (no OpenAI needed):
For these tasks, read the transcript/timestamps and generate content using the linked templates:

- **Description**: See [templates/description.md](templates/description.md)
- **SEO Keywords**: See [templates/seo-keywords.md](templates/seo-keywords.md)
- **LinkedIn/Twitter Posts**: See [templates/social-posts.md](templates/social-posts.md)
- **Context Cards**: See [templates/context-cards.md](templates/context-cards.md)

### Note on CLI commands
The CLI has commands like `generate description`, `generate context-cards` that use OpenAI. These exist for manual CLI usage. If user explicitly requests a CLI command, honor the request (it may require OpenAI key). Otherwise, generate content directly.

---

## Output Location

Before generating files (transcripts, descriptions, timestamps, etc.), if not especified before, ask the user where to save them using AskUserQuestion.

**Example prompt:**
"Where should I save the output files?"
- Option 1: "Current directory" - save in `.` or `./output/`
- Option 2: "Same folder as video" - save alongside the source video
- Option 3: "I'll specify a path" - user provides custom location

**Default behavior if user doesn't specify:** Ask rather than assuming temp directory.

---

## Long-Running Operations: Use tmux

For downloads and any potentially long-running video operation, run the command inside a named `tmux` session instead of blocking the agent shell. This includes YouTube/video downloads, uploads, silence removal, audio enhancement, transcription, and large renders/transcodes.

Recommended pattern:
```bash
# Start the job in the background
tmux new-session -d -s video_download 'video-tool video download -u "URL" -o "./output/video.mp4"'

# Check progress/log output
tmux capture-pane -pt video_download

# Reattach if needed
tmux attach -t video_download

# Clean up after completion
tmux kill-session -t video_download
```

Use descriptive session names like `video_download`, `video_transcribe`, `video_upload`, or `video_process_<slug>`. After launching the tmux job, monitor it with `tmux capture-pane -pt <session>` until it finishes, then verify the expected output file exists.

---

### YouTube Authentication

For YouTube uploads, run OAuth2 setup:
```bash
video-tool config youtube-auth
```

---

## Command Reference

### Video Processing

#### Download Video
Download from YouTube or other supported sites.
```bash
video-tool video download -u "URL" -o ./output/my-video.mp4
video-tool video download -u "URL" -o ./output/%(title)s.%(ext)s
```
| Option | Description |
|--------|-------------|
| `-u, --url` | Video URL |
| `-o, --output-path` | Output file path (directory uses title template; default is `./output/%(title)s.%(ext)s`) |

#### Get Video Info
Get metadata: duration, resolution, codec, bitrate.
```bash
video-tool video info -i video.mp4
```

#### Remove Silence
Remove silent segments from video.
```bash
video-tool video silence-removal -i input.mp4 -o output.mp4 -t 1.0
```
| Option | Description |
|--------|-------------|
| `-i, --input` | Input video |
| `-o, --output-path` | Output path |
| `-t, --threshold` | Min silence duration to remove (default: 1.0s) |

#### Trim Video
Cut from start and/or end of video.
```bash
video-tool video trim -i input.mp4 -o output.mp4 -s 00:00:10 -e 00:05:00
```
| Option | Description |
|--------|-------------|
| `-s, --start` | Start timestamp (HH:MM:SS, MM:SS, or seconds) |
| `-e, --end` | End timestamp |
| `-g, --gpu` | Use GPU acceleration |

#### Extract Segment
Keep only a specific portion of video.
```bash
video-tool video extract-segment -i input.mp4 -o output.mp4 -s 00:01:00 -e 00:02:30
```

#### Cut Segment
Remove a middle portion from video.
```bash
video-tool video cut -i input.mp4 -o output.mp4 -f 00:01:00 -t 00:02:00
```
| Option | Description |
|--------|-------------|
| `-f, --from` | Start of segment to remove |
| `-t, --to` | End of segment to remove |

#### Change Speed
Speed up or slow down video.
```bash
video-tool video speed -i input.mp4 -o output.mp4 -f 1.5
```
| Option | Description |
|--------|-------------|
| `-f, --factor` | Speed factor (0.25-4.0). 2.0=double, 0.5=half |
| `-p, --preserve-pitch` | Keep original audio pitch (default: yes) |

#### Concatenate Videos
Join multiple videos into one.
```bash
video-tool video concat -i ./clips/ -o ./output/final.mp4 -f
```
| Option | Description |
|--------|-------------|
| `-i, --input-dir` | Directory containing videos |
| `-o, --output-path` | Output file path |
| `-f, --fast-concat` | Skip re-encoding (faster, requires same codec) |

### Audio Operations

#### Extract Audio
Extract audio track to MP3.
```bash
video-tool video extract-audio -i video.mp4 -o audio.mp3
```

#### Enhance Audio
Improve audio quality using Resemble AI (requires Replicate API token).
```bash
video-tool video enhance-audio -i input.mp4 -o enhanced.mp4
video-tool video enhance-audio -i input.mp4 -o denoised.mp4 -d  # denoise only
```

#### Replace Audio
Swap audio track in a video.
```bash
video-tool video replace-audio -v video.mp4 -a new_audio.mp3 -o output.mp4
```

### Transcription & Timestamps

#### Generate Transcript
Create VTT captions with an automatically selected installed runtime, an explicit local model, or Groq.

Before the first transcription on a machine, inspect the recommendation and available model IDs:
```bash
video-tool config transcription --recommend
video-tool config transcription --list-models
```

Install the appropriate optional runtime when local transcription is desired:
```bash
# Apple Silicon: MLX Parakeet (English) and MLX Whisper (multilingual)
uv tool install --force 'video-tool[transcription-mlx] @ git+https://github.com/alejandro-ao/video-tool-cli.git'

# Portable CPU/CUDA Whisper
uv tool install --force 'video-tool[transcription-faster-whisper] @ git+https://github.com/alejandro-ao/video-tool-cli.git'

# Standard Hugging Face Transformers Whisper
uv tool install --force 'video-tool[transcription-transformers] @ git+https://github.com/alejandro-ao/video-tool-cli.git'

# NVIDIA NeMo Parakeet on Linux/CUDA
uv tool install --force 'video-tool[transcription-nemo] @ git+https://github.com/alejandro-ao/video-tool-cli.git'
```

Transcribe using automatic selection or an explicit model:
```bash
video-tool generate transcript -i video.mp4 -o transcript.vtt
video-tool generate transcript -i video.mp4 -o transcript.vtt -m mlx/parakeet-tdt-0.6b-v2 --language en
video-tool generate transcript -i video.mp4 -o transcript.vtt -m mlx/whisper-large-v3-turbo --language es
video-tool generate transcript -i video.mp4 -o transcript.vtt -m groq/whisper-large-v3-turbo
```

Model guidance:
- Apple Silicon + English: `mlx/parakeet-tdt-0.6b-v2`
- Apple Silicon + multilingual: `mlx/whisper-large-v3-turbo`
- Portable CPU/CUDA: `faster-whisper/large-v3-turbo`
- Standard Transformers/MPS/CUDA: `transformers/whisper-large-v3-turbo`
- NVIDIA Linux/CUDA + English: `nemo/parakeet-tdt-0.6b-v2`
- No local runtime or remote preference: `groq/whisper-large-v3-turbo`

Parakeet TDT 0.6B V2 is English-only. Models download on first use and are cached locally. Missing optional runtimes produce an installation command. Only Groq transcription requires a Groq API key.

Advanced options:
| Option | Description |
|--------|-------------|
| `--backend` | Backend override: `auto`, `groq`, `mlx-parakeet`, `mlx-whisper`, `faster-whisper`, `transformers`, `nemo` |
| `-m, --model` | Registered model ID; preferred over selecting only a backend |
| `--language` | `auto` or a language code such as `en`, `es`, or `fr` |
| `--device` | `auto`, `cpu`, `mps`, or `cuda` |
| `--compute-type` | Runtime precision such as `float16` or `int8` |

Persist or inspect defaults:
```bash
video-tool config transcription --model mlx/parakeet-tdt-0.6b-v2 --language en
video-tool config transcription --show
video-tool config transcription --reset
```

When operating this skill, prefer the recommended local model when its runtime is installed. Ask before installing a large optional runtime or downloading model weights. Use Groq if the user prefers remote processing or local hardware/runtime is unsuitable.

#### Generate Timestamps
Create chapter markers (requires OpenAI API key for transcript mode).
```bash
# From video clips directory
video-tool video timestamps -m clips -i ./clips/ -o timestamps.json

# From transcript
video-tool video timestamps -m transcript -i transcript.vtt -o timestamps.json -g medium
```
| Option | Description |
|--------|-------------|
| `-m, --mode` | `clips` or `transcript` |
| `-g, --granularity` | `low`, `medium`, `high` (transcript mode) |
| `-n, --notes` | Additional instructions for LLM |

### Uploads

#### YouTube Upload
Upload video as draft (requires OAuth2 auth via `video-tool config youtube-auth`).
```bash
video-tool upload youtube-video -i video.mp4 -t "Title" -d "Description" -p private
video-tool upload youtube-video -i video.mp4 --metadata-path metadata.json
```
| Option | Description |
|--------|-------------|
| `-t, --title` | Video title |
| `-d, --description` | Description text |
| `--description-file` | Read description from file |
| `--tags` | Comma-separated tags |
| `--tags-file` | Tags from file (one per line) |
| `-c, --category` | YouTube category ID (default: 27 Education) |
| `-p, --privacy` | `private` (draft) or `unlisted` only |
| `--thumbnail` | Thumbnail image path |

#### YouTube Metadata Update
Update existing video metadata.
```bash
video-tool upload youtube-metadata -v VIDEO_ID --description-file description.md
```

#### YouTube Transcript Upload
Add captions to YouTube video.
```bash
video-tool upload youtube-transcript -v VIDEO_ID -t transcript.vtt -l en
```

#### Bunny.net Uploads
Upload to Bunny.net CDN (requires Bunny credentials via `config keys`).
```bash
video-tool upload bunny-video -v video.mp4
video-tool upload bunny-transcript -v VIDEO_ID -t transcript.vtt
video-tool upload bunny-chapters -v VIDEO_ID -c timestamps.json
```

#### X (Twitter) Post
Post a thread to X (Twitter) (requires X OAuth via `video-tool config x-auth`).
```bash
video-tool upload x --text "First post" --thread-item "Follow-up" --video-path video.mp4
video-tool upload twitter --text-file post.txt --thread-file thread.txt
```
| Option | Description |
|--------|-------------|
| `--text` / `--text-file` | First post text |
| `--thread-item` / `--thread-file` | Additional thread items (repeatable or `---` delimiter) |
| `--video-path` / `--video-url` | Video file or URL to include |
| `--output-dir` | Output directory for metadata |

#### LinkedIn Post
Publish a LinkedIn post (requires LinkedIn credentials via `video-tool config keys`).
```bash
video-tool upload linkedin --text-file post.md --video-path video.mp4
```
| Option | Description |
|--------|-------------|
| `--text` / `--text-file` | Post text |
| `--video-path` / `--video-url` | Video file or URL to include |
| `--output-dir` | Output directory for metadata |
| `--access-token` | Override access token |
| `--author-urn` | Override author URN |

### Configuration

```bash
video-tool config keys                        # Configure API keys (interactive)
video-tool config keys --set KEY=VALUE        # Set key non-interactively
video-tool config keys --show                 # View configured keys
video-tool config llm                         # Configure LLM settings and persistent links
video-tool config transcription --recommend  # Recommend a transcription model
video-tool config transcription --list-models # List supported transcription models
video-tool config transcription --show       # Show saved transcription defaults
video-tool config x-auth                      # Set up X OAuth credentials
video-tool config youtube-auth                # Set up YouTube OAuth2
video-tool config youtube-status              # Check YouTube credentials
```

---

## Command Templates for Skills

Common tasks that other skills can reference by name.

### Transcribe Video
Generate a VTT transcript from a video/audio file using automatic selection or an explicit model.
```bash
video-tool config transcription --recommend
video-tool generate transcript -i <INPUT_FILE> -o <OUTPUT_FILE> [-m <MODEL_ID>] [--language <LANGUAGE>]
```
**Inputs:**
- `<INPUT_FILE>`: Path to video or audio file
- `<OUTPUT_FILE>`: Path to output VTT file
- `<MODEL_ID>`: Optional registered local or Groq model ID
- `<LANGUAGE>`: Optional language code; use `en` with Parakeet

**Requirements:** The selected local runtime extra, or a Groq API key only when selecting Groq

---

### Concatenate Videos
Join multiple video clips into single file.
```bash
video-tool video concat -i <INPUT_DIR> -o <OUTPUT_FILE> --fast-concat
```
**Inputs:**
- `<INPUT_DIR>`: Directory with numbered clips (01-*.mp4, 02-*.mp4, etc.)
- `<OUTPUT_FILE>`: Path to output video file
- `--fast-concat`: Skip reprocessing (optional, recommended for speed)

**Note:** Clips must be named with numeric prefixes for correct ordering.

---

### Generate Timestamps from Clips
Create chapter timestamps from clip filenames.
```bash
video-tool video timestamps --mode clips -i <INPUT_DIR> -o <OUTPUT_FILE>
```
**Inputs:**
- `<INPUT_DIR>`: Directory with numbered clips
- `<OUTPUT_FILE>`: Path to output JSON file

**Output Format:**
```json
{
  "timestamps": [
    {"time": "00:00:00", "title": "Introduction"},
    {"time": "00:05:30", "title": "Main Content"}
  ]
}
```

---

### Upload to YouTube
Upload video with metadata to YouTube.
```bash
video-tool upload youtube-video \
  -i <VIDEO_FILE> \
  -t "<TITLE>" \
  --description-file <DESCRIPTION_FILE> \
  --tags-file <TAGS_FILE> \
  --privacy <PRIVACY>
```
**Inputs:**
- `<VIDEO_FILE>`: Path to video file
- `<TITLE>`: Video title (quoted)
- `<DESCRIPTION_FILE>`: Path to markdown description file
- `<TAGS_FILE>`: Path to text file with tags (one per line)
- `<PRIVACY>`: `private`, `unlisted`, or `public`

**Requirements:** YouTube OAuth2 authentication (`video-tool config youtube-auth`)

**Output:** JSON with video_id and url (save to youtube-upload.json for publish skill)

---

## Common Workflows

See [workflows.md](workflows.md) for detailed examples.

