/watch
No tienes una entrada de video; esta skill te la proporciona. Un script de Python obtiene primero los subtítulos, opcionalmente descarga el video, extrae fotogramas como JPEG (con detección de escenas o fotogramas clave rápidos en modo eficiente), obtiene una transcripción con marcas de tiempo (priorizando subtítulos nativos, luego la API de Whisper como respaldo), e imprime las rutas de los fotogramas. Luego Lee cada ruta de fotograma para ver las imágenes y combinarlas con la transcripción para responder al usuario.
Resuelve SKILL_DIR (haz esto antes de cualquier comando)
Cada comando python3 ... a continuación ejecuta un script incluido en SKILL_DIR/scripts/. Establece SKILL_DIR en la ruta absoluta del directorio que contiene este SKILL.md que acabas de Leer — tu sistema te indicó esa ruta en el resultado de la Lectura. Los scripts siempre están en un directorio hermano directo de este archivo (SKILL_DIR/scripts/watch.py), en cualquier diseño de instalación:
Read ~/.claude/plugins/cache/claude-video/watch/<ver>/skills/watch/SKILL.md → SKILL_DIR=…/skills/watch
Read ~/.codex/skills/watch/SKILL.md → SKILL_DIR=~/.codex/skills/watch
Read ~/.agents/skills/watch/SKILL.md → SKILL_DIR=~/.agents/skills/watch
Sustituye esa ruta literal por ${SKILL_DIR} en cada comando. Esto funciona en cualquier sistema (Claude Code, Codex, Cursor, Gemini CLI, …) sin depender de ninguna variable de entorno específica del sistema. Verifica una vez al inicio de una ejecución:
SKILL_DIR="<ruta absoluta del directorio que contiene el SKILL.md que Leíste>"
if [ ! -f "$SKILL_DIR/scripts/watch.py" ]; then
echo "ERROR: scripts/watch.py no encontrado en SKILL_DIR=$SKILL_DIR" >&2
echo "Vuelve a verificar el directorio del SKILL.md que Leíste y sustitúyelo como SKILL_DIR." >&2
exit 1
fi
Paso 0 — Verificación preliminar (se ejecuta en cada invocación de /watch, silencioso si tiene éxito)
Intérprete de Python: cada comando python3 ... en esta skill es para macOS/Linux. En Windows, sustituye con python — el comando python3 en Windows es el stub de Microsoft Store y no ejecutará el script.
En la primera invocación de /watch en una sesión, usa la verificación estructurada para detectar la configuración inicial:
python3 "${SKILL_DIR}/scripts/setup.py" --json
Rama según dos campos:
can_proceed: trueyfirst_run: false→ la configuración ya está hecha (el usuario puede haber omitido deliberadamente una clave de Whisper; eso está permitido). Continúa al Paso 1 sin comentarios.first_run: true→ configuración genuina por primera vez. Haz esto en orden:- Si
missing_binariesno está vacío, ejecuta primero el instalador (se autoinstala en macOS / imprime comandos en otros sistemas — ver más abajo) y confirma que los binarios se hayan instalado. No te saltes esto y vayas directamente a las preferencias. - Ejecuta el instalador una vez más si es necesario para que cree
~/.config/watch/.env(solo escribe la plantilla cuando el archivo no existe, así que déjalo crear el archivo antes de que escribas cualquier valor en él). - Anima al usuario a proporcionar una clave de API de Whisper y haz las preguntas de preferencia de visualización a continuación, luego escribe los valores seleccionados en
~/.config/watch/.envy estableceSETUP_COMPLETE=true.
- Si
can_proceed: falseyfirst_run: false→ la configuración se completó antes pero el entorno ha retrocedido (por ejemplo,missing_binariesdespués de un cambio de SO). Ejecuta el instalador para remediarlo, luego continúa. No vuelvas a preguntar las preferencias.
La falta de una clave de Whisper es algo que se debe alentar a solucionar, no un requisito: en una primera ejecución genuina, status mostrará needs_key incluso cuando los binarios estén presentes; esa es tu señal para alentar una clave, no un bloqueo.
En llamadas posteriores a /watch en la misma sesión, usa la verificación silenciosa:
python3 "${SKILL_DIR}/scripts/setup.py" --check
Esto es una búsqueda de <100ms. Salida 0 significa que /watch puede ejecutarse — esto incluye a un usuario que completó la configuración sin una clave de Whisper (sin clave está permitido). Con salida 0, el script no emite nada — continúa al Paso 1 sin comentarios. NO anuncies "la configuración está completa" al usuario — no necesita un mensaje de estado en cada turno. La única salida visible para el usuario aceptable del Paso 0 es cuando se requiere una corrección.
Con salida distinta de cero, sigue la tabla:
| Salida | Significado | Acción |
|---|---|---|
2 | Faltan binarios (ffmpeg / ffprobe / yt-dlp) | Ejecuta el instalador |
3 | Primera ejecución genuina sin clave de API de Whisper | Ejecuta el instalador para crear .env, luego alienta una clave (el usuario puede rechazarla — continúa con --no-whisper) |
4 | Ambos faltan | Ejecuta el instalador, luego alienta una clave |
La salida 3 solo se activa antes de que el usuario haya completado la configuración. Una vez que se escribe SETUP_COMPLETE=true, una instalación sin clave devuelve salida 0 y nunca se vuelve a molestar.
El instalador es idempotente — seguro de volver a ejecutar:
python3 "${SKILL_DIR}/scripts/setup.py"
En macOS con Homebrew, instala automáticamente ffmpeg y yt-dlp. En Linux/Windows, imprime los comandos de instalación exactos para que el usuario los ejecute. Crea ~/.config/watch/.env con marcadores de posición comentados y configuraciones predeterminadas de visualización con permisos 0600.
Si todavía falta una clave de API después de la instalación: usa AskUserQuestion para preguntar al usuario si tiene una clave de API de Groq (preferida — más barata, más rápida) o una clave de OpenAI. Luego escríbela en ~/.config/watch/.env — establece la línea correspondiente GROQ_API_KEY=... o OPENAI_API_KEY=.... Si no quieren configurar Whisper, continúa con --no-whisper e indícales que los videos sin subtítulos nativos solo devolverán fotogramas.
Preferencia de visualización en la primera ejecución: después de que el instalador haya creado ~/.config/watch/.env, usa AskUserQuestion para hacer una pregunta:
- Detalle predeterminado (un dial). Presenta estas opciones de
AskUserQuestionen este orden exacto — de más ligero a más pesado — y mantén(recomendado)enbalancedaunque no sea el primero (no reordenes para poner la opción recomendada primero):transcript— sin fotogramas, solo transcripción (omite la descarga del video cuando existen subtítulos).efficient— pase rápido de fotogramas clave (límite 50).balanced(recomendado) — fotogramas con detección de escenas (límite 100, predeterminado).token-burner— con detección de escenas, sin límite (máxima fidelidad; alto costo de tokens).
Escribe la respuesta directamente en ~/.config/watch/.env estableciendo la clave simple en su propia línea — sin comentario inline al final (un # nota después del valor puede romper el análisis):
WATCH_DETAIL=balanced
Usa el valor seleccionado por el usuario. Si omiten la pregunta, mantén el valor predeterminado recomendado. Una vez que se hayan manejado las dependencias, la elección de la clave API y esta preferencia, escribe o actualiza SETUP_COMPLETE=true en el mismo archivo. No vuelvas a hacer esta pregunta de preferencia cuando SETUP_COMPLETE=true.
Modo estructurado (opcional): python3 "${SKILL_DIR}/scripts/setup.py" --json emite {status, can_proceed, first_run, setup_complete, missing_binaries, whisper_backend, has_api_key, config_file, watch_detail, platform} donde status es uno de ready | needs_install | needs_key | needs_install_and_key. status describe el estado ideal (se alienta una clave, por lo que una primera ejecución sin clave lee needs_key); can_proceed es la puerta operativa (binarios presentes Y una clave está establecida O la configuración ya se completó). Ramifica según can_proceed/first_run para decidir si ejecutar; usa status para decidir qué alentar.
Dentro de una misma sesión, puedes omitir el Paso 0 en llamadas posteriores a /watch — una vez que --check devolvió 0, nada del entorno cambia entre turnos.
Cuándo usarlo
- El usuario pega una URL de video (YouTube, Vimeo, X, TikTok, clip de Twitch, la mayoría de sitios compatibles con yt-dlp) y pregunta sobre él.
- El usuario señala un archivo de video local (
.mp4,.mov,.mkv,.webm, etc.) y pregunta sobre él. - El usuario escribe
/watch <url-o-ruta> [pregunta].
Límites recomendados
- Mejor precisión: videos de menos de 10 minutos. La cobertura de fotogramas se escala inversamente con la duración.
- Límite de velocidad universal: 2 fps. El script nunca muestrea más rápido de 2 fps, incluso cuando un presupuesto o
--fpsimplicaría más. - El límite de fotogramas lo establece el modo de detalle (
WATCH_DETAILen~/.config/watch/.env, o--detail), no un solo límite global:transcript→ sin fotogramasefficient→ hasta 50 (fotogramas clave)balanced(predeterminado) → hasta 100 (detección de escenas)token-burner→ sin límite (detección de escenas; se imprime una advertencia suave más allá de 250 fotogramas)--max-frames Nanula el límite que el modo usaría de otra manera.
- Presupuesto de fotogramas para video completo por duración. El costo de tokens crece con el número de fotogramas, por lo que el script apunta a un presupuesto por duración. Este presupuesto establece los fps y el respaldo de muestreo uniforme; la selección con detección de escenas puede llenar hasta el límite de detalle anterior, el que sea menor:
- ≤30s → ~12-30 fotogramas
- 30s-1min → ~40 fotogramas
- 1-3min → ~60 fotogramas
- 3-10min → ~80 fotogramas
- >10min → hasta el límite de detalle, espaciados (se imprime una advertencia)
- Si el usuario te entrega un video largo, considera preguntar si quiere una sección específica antes de gastar tokens en un escaneo disperso.
Cómo invocar
Paso 1 — analiza la entrada del usuario. Separa la fuente del video (URL o ruta) de cualquier pregunta que haya hecho el usuario. Ejemplo: /watch https://youtu.be/abc ¿en qué idioma está esto? → fuente = https://youtu.be/abc, pregunta = ¿en qué idioma está esto?.
Paso 2 — ejecuta el script de visualización. Pasa la fuente textualmente. No hagas escape de shell por tu cuenta más allá del entrecomillado normal:
python3 "${SKILL_DIR}/scripts/watch.py" "<fuente>"
Banderas opcionales:
--detail transcript|efficient|balanced|token-burner— dial de fidelidad/velocidad.transcript= sin fotogramas (solo transcripción, omite la descarga del video cuando existen subtítulos);efficient= fotogramas clave rápidos (límite 50);balanced= fotogramas con detección de escenas (límite 100);token-burner= detección de escenas, sin límite.--start T/--end T— enfócate en una sección. AceptaSS,MM:SS, oHH:MM:SS. Cuando se establece alguno, los fps se escalan automáticamente más densos (ver "Enfocándose en una sección" más abajo).--timestamps T1,T2,…— captura un fotograma en cada una de estas marcas de tiempo absolutas (SS,MM:SS, oHH:MM:SS). Úsalo después de leer la transcripción para capturar momentos deícticos que el presentador señala ("mira aquí", "como puedes ver", "nota esto") que la selección visual por sí sola podría pasar por alto. Ver "Fotogramas con indicación de transcripción" más abajo.--max-frames N— anula el límite preestablecido para un presupuesto de tokens más ajustado (ej.--max-frames 40)--resolution W— cambia el ancho del fotograma en píxeles (predeterminado 512; aumenta a 1024 solo si el usuario necesita leer texto en pantalla)--fps F— anula los fps automáticos (limitado a 2 fps máx.)--out-dir DIR— mantener los archivos de trabajo en algún lugar específico (predeterminado: un directorio tmp generado automáticamente)--whisper groq|openai— fuerza un backend de Whisper específico (predeterminado: prefiere Groq si ambas claves existen)--no-whisper— deshabilita completamente el respaldo de Whisper (solo fotogramas si no hay subtítulos)--no-dedup— mantiene fotogramas casi duplicados. Por defecto, un pase de diferencia de fotogramas elimina aquellos visualmente casi idénticos al anterior (diapositivas fijas, grabaciones de pantalla estáticas, video pausado) para que el presupuesto de fotogramas se destine a contenido distinto; la línea de Fotogramas del informe indica cuántos se eliminaron. Pasa esto solo si el usuario necesita cada fotograma muestreado (ej. juzgando movimiento sutil entre fotogramas).
Enfocándose en una sección (mayor velocidad de fotogramas)
Cuando el usuario pregunta sobre un momento específico — "¿qué sucede en el minuto 2?", "acércate a 0:45 a 1:00", "los primeros 10 segundos" — pasa --start y/o --end. El script cambia a presupuestos de modo enfocado, que son más densos que los de video completo (aún limitados a 2 fps, y aún limitados por el límite del modo de detalle — los conteos a continuación asumen el límite predeterminado de balanced de 100; efficient tiene un máximo de 50):
- ≤5s → 2 fps (hasta 10 fotogramas)
- 5-15s → 2 fps (hasta 30 fotogramas)
- 15-30s → ~2 fps (hasta 60 fotogramas)
- 30-60s → ~1.3 fps (hasta 80 fotogramas)
- 60-180s → ~0.6 fps (100 fotogramas, con límite)
El modo enfocado es la opción correcta para:
- Cualquier momento/rango que el usuario nombre explícitamente ("alrededor de 2:30", "la introducción", "los últimos 30 segundos").
- Cualquier video de más de ~10 minutos donde la pregunta del usuario sea sobre una parte específica — ejecutar enfocado en la sección relevante es mucho más útil que un escaneo disperso de todo el video.
- Re-ejecuciones después de que un escaneo completo no tuviera suficiente detalle en alguna región.
La transcripción se filtra automáticamente al mismo rango. Las marcas de tiempo de los fotogramas son absolutas (línea de tiempo real del video, no desplazadas desde el inicio).
Ejemplos:
# Últimos 10 segundos de un video de 1 minuto
python3 "${SKILL_DIR}/scripts/watch.py" video.mp4 --start 50 --end 60
# Acércate a 2:15 → 2:45 a 2 fps (60 fotogramas)
python3 "${SKILL_DIR}/scripts/watch.py" "$URL" --start 2:15 --end 2:45 --fps 2
# Desde 1h12m hasta el final del video
python3 "${SKILL_DIR}/scripts/watch.py" "$URL" --start 1:12:00
Paso 3 — Lee cada ruta de fotograma que el script liste. La herramienta de Lectura renderiza los JPEG directamente como imágenes para ti. Lee todos los fotogramas en un solo mensaje (llamadas de herramienta paralelas) para que los veas juntos. Los fotogramas están en orden cronológico con una marca de tiempo t=MM:SS para que puedas alinearlos con la transcripción.
Paso 4 — responde al usuario. Ahora tienes dos flujos de evidencia:
- Fotogramas — lo que está en pantalla en cada marca de tiempo
- Transcripción — lo que se dice en cada marca de tiempo. El encabezado del informe muestra la fuente (
captions= yt-dlp extrajo subtítulos nativos;whisper (groq)owhisper (openai)= transcrito por API).
Si el usuario hizo una pregunta específica, respóndela directamente citando marcas de tiempo. Si no preguntó nada, resume lo que sucede en el video — estructura, momentos clave, visuales notables, contenido hablado.
Esto también se aplica al detalle transcript: incluso sin fotogramas, produce un resumen como los otros modos — no pegues la transcripción completa en el chat. Sintetiza la estructura, los momentos clave y el contenido hablado con marcas de tiempo; cita solo las líneas que importan. Ofrece la transcripción sin procesar solo si el usuario la solicita explícitamente.
Paso 5 — limpia. El script imprime un directorio de trabajo al final. Si el usuario no va a hacer preguntas de seguimiento sobre este video, bórralo con rm -rf <dir>. Si es posible que lo haga, déjalo en su lugar.
Detalle y fotogramas
El comportamiento predeterminado proviene de ~/.config/watch/.env:
WATCH_DETAIL=transcript|efficient|balanced|token-burner(predeterminado:balanced)
En efficient se conserva el ancho de la imagen (512px). En balanced y token-burner, la detección de escenas puede producir fotogramas de diferentes dimensiones si la escena cambia
... [truncado para traducción]