Video & Audio
Hook
Hooks
What claude-video runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.
Install
$ npx -y skills add AgriciDaniel/claude-video --agent claude-codeShips with claude-video. Installing the plugin gets these hooks.
What fires, and when
PostToolUse
- Matches
Edit|Writepython3 ~/.claude/skills/claude-video/hooks/validate-skillmd.py "$FILE_PATH"
PreToolUse
- Matches
Bashbash ~/.claude/skills/claude-video/hooks/preflight-check.sh "$COMMAND"
Where it lives
- hooks/preflight-check.shRunsGitHub
Read the script
#!/usr/bin/env bash # Pre-tool-use safety check for FFmpeg commands in Claude Video. # # Blocks dangerous patterns: # - Writing to input file (overwrite source) # - Missing -n flag (no-overwrite safety) # - rm -rf on media directories # - Unquoted glob expansions on video files # # Hook configuration in ~/.claude/settings.json: # { # "hooks": { # "PreToolUse": [ # { # "matcher": "Bash", # "hooks": [ # { # "type": "command", # "command": "bash ~/.claude/skills/claude-video/hooks/preflight-check.sh \"$COMMAND\"", # "exitCodes": { "2": "block" } # } # ] # } # ] # } # } set -euo pipefail COMMAND="${1:-}" # Skip if not a video-related command if ! echo "$COMMAND" | grep -qiE '(ffmpeg|ffprobe|remotion|npx remotion)'; then exit 0 fi # Block: FFmpeg writing to same file as input if echo "$COMMAND" | grep -qP 'ffmpeg\s.*-i\s+"?([^\s"]+)"?\s.*\s\1\s*$'; then echo "x BLOCKED: FFmpeg output path matches input path. This would destroy the source file." echo " Use a different output filename, then rename after verification." exit 2 fi # Warn: FFmpeg without -n (no-clobber) flag if echo "$COMMAND" | grep -qE '^ffmpeg\s' && ! echo "$COMMAND" | grep -qE '\s-n\s|\s-y\s'; then echo "~ WARNING: FFmpeg command missing -n (no-clobber) or -y (overwrite) flag." echo " Convention: always use -n to prevent accidental overwrites." exit 1 fi # Block: rm -rf on common media directories if echo "$COMMAND" | grep -qiE 'rm\s+-rf?\s+.*(public/stock|public/music|public/voiceover|output|out/)'; then echo "x BLOCKED: Destructive rm on media directory. Review and delete specific files instead." exit 2 fi exit 0 - hooks/validate-skillmd.pyRunsGitHub
Read the script
#!/usr/bin/env python3 """Post-edit SKILL.md validation hook for Claude Code. Validates SKILL.md frontmatter after file edits. Returns exit code 2 to block if critical validation errors found. Hook configuration in ~/.claude/settings.json: { "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "python3 ~/.claude/skills/claude-video/hooks/validate-skillmd.py \"$FILE_PATH\"", "exitCodes": { "2": "block" } } ] } ] } } Checks: - Valid YAML frontmatter with --- delimiters - Required fields: name, description - Line count under 500 (convention) - No hardcoded user paths (/home/username/...) - No API keys or tokens in content """ import re import sys import os def validate_skillmd(filepath: str) -> tuple[list[str], list[str]]: """Validate a SKILL.md file. Returns (errors, warnings).""" errors = [] warnings = [] try: with open(filepath, "r", encoding="utf-8", errors="ignore") as f: content = f.read() lines = content.split("\n") except (OSError, IOError): return [], [] # Check frontmatter exists if not content.startswith("---"): errors.append("Missing YAML frontmatter (must start with ---)") return errors, warnings # Find closing --- second_delim = content.find("---", 3) if second_delim == -1: errors.append("Unclosed YAML frontmatter (missing closing ---)") return errors, warnings frontmatter = content[3:second_delim].strip() # Check required fields if not re.search(r"^name:\s*\S", frontmatter, re.MULTILINE): errors.append("Missing required field: name") if not re.search(r"^description:", frontmatter, re.MULTILINE): errors.append("Missing required field: description") # Line count check line_count = len(lines) if line_count > 500: warnings.append(f"SKILL.md is {line_count} lines (convention: <500)") # Hardcoded path check home_pattern = re.compile(r"/home/\w+/|/Users/\w+/|C:\\Users\\\w+\\") for i, line in enumerate(lines, 1): if home_pattern.search(line): # Allow paths in comments explaining examples if not line.strip().startswith("#"): errors.append( f"Line {i}: Hardcoded user path found. " "Use relative paths or ~ instead" ) # Credential check secret_patterns = [ (r"['\"][A-Za-z0-9]{32,}['\"]", "Possible API key/token"), (r"(password|secret|token)\s*[:=]\s*['\"][^'\"]+['\"]", "Hardcoded credential"), ] for pattern, label in secret_patterns: for i, line in enumerate(lines, 1): if re.search(pattern, line, re.IGNORECASE): # Skip if it looks like an env var reference if "$" in line or "env" in line.lower() or "ENV" in line: continue warnings.append(f"Line {i}: {label} detected. Use env vars instead") return errors, warnings def main(): if len(sys.argv) < 2: sys.exit(0) filepath = sys.argv[1] if not os.path.isfile(filepath): sys.exit(0) # Only validate SKILL.md files if not filepath.endswith("SKILL.md"): sys.exit(0) errors, warnings = validate_skillmd(filepath) if warnings: for w in warnings: print(f" ~ {w}") if errors: print("SKILL.md validation errors (blocking):") for e in errors: print(f" x {e}") sys.exit(2) if not warnings: sys.exit(0) sys.exit(1) # Warnings only, proceed if __name__ == "__main__": main()
Read the script before you install anything that runs on your machine. This is the one part of a plugin that acts without being asked.
Ships withclaude-video
AI-powered video production suite for Claude Code. Edit, transcode, caption, analyze, generate, and create promo videos: all from your terminal.
Get the whole plugin
Stats
31
Stars
12
Forks
Quiet
Maintenance
Python
Language
MIT
License
6mo ago
Last commit
6mo ago
Created
4h ago
Added

