CommunityProgramación y desarrollogithub.com

skailabinfo/claude-video-harness

Configuración inicial del proyecto para un nuevo usuario: verificación del entorno, entrevista detallada (quién eres, ~10 reels de referencia, análisis de gusto, transcripción, conexión de servicios con verificación de acceso, paleta, tipografías, subtítulos, gráficos, movimiento, sonido), mostrando opciones con fotogramas ya renderizados; genera harness.config.json, brand-kit.md, editing-taste.md, exemplars.md. Ejecútalo cuando en harness.config.json "configured" sea false, o cuando el usuario pida reconfigurar el proyecto, cambiar el estilo, o analizar las referencias de nuevo.

¿Qué es claude-video-harness?

Esta habilidad para Claude Code transforma un clon limpio de un pipeline de edición de video vertical ("talking head" para Reels, TikTok, Shorts) en un sistema personalizado para un creador específico. Realiza una configuración completa que incluye: verificación del entorno de desarrollo (Node.js, ffmpeg, etc.), una entrevista profunda para entender la marca del usuario (nombre, tono, audiencia), análisis de aproximadamente 10 reels de referencia (descarga automática y extracción de métricas como tempo, paleta de colores, ritmo de edición), elección de servicios externos (ElevenLabs para transcripción y voz, Higgsfield para B-roll, 21st.dev para componentes React, Buffer para programación de publicaciones), selección de paleta de colores (con verificación de contraste) y tipografías (con soporte de alfabeto), y definición del estilo de edición (subtítulos, gráficos, movimiento). Todo se muestra visualmente mediante fotogramas de ejemplo generados con Remotion, evitando suposiciones sobre el usuario y manteniendo sus preferencias como punto central. Al finalizar, genera archivos de configuración clave (harness.config.json, brand-kit.md, editing-taste.md, exemplars.md) que alimentan el pipeline de edición.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/skailabinfo/claude-video-harness/tree/HEAD/.claude/skills/setup

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Configuración del proyecto

Objetivo: convertir un clon limpio en un pipeline que edite al estilo de esta persona — entender lo que le gusta, conectar sus servicios y mostrar fotogramas de su futuro video. Habla en el idioma del usuario, de forma breve y humana.

El proyecto no tiene estilo propio. Todo lo relacionado con la apariencia del video — paleta, tipografías, subtítulos, tarjetas, stickers, póster, tempo, punch-ins, gradación, sonido — lo elige el usuario o se toma de sus referencias. No ofrezcas una opción «estándar» o «popular», no impongas tus preferencias ni nada de lo que ya esté en el proyecto (los valores por defecto en harness.config.json y la demo no son un estilo, sino un espacio vacío).

Reglas de la entrevista

  • Un bloque, un mensaje; los bloques nunca se combinan. No pongas dos bloques en un solo AskUserQuestion: las personas tienden a marcar la primera opción en preguntas en grupo. Los bloques 4 (servicios), 6 (paleta), 7 (tipografías), 8 (estilo de edición) son conversaciones de múltiples mensajes.
  • Sin etiquetas «(recomiendo)» en cuestiones de gusto. La etiqueta solo está permitida para opciones puramente técnicas — método de transcripción (bloque 3). En colores, tipografías, estilo, servicios y preguntas sobre la persona, no la uses; describe las opciones de forma neutral, explicando qué ofrece cada una.
  • Las opciones se basan en las respuestas y referencias del usuario. Si no hay respuestas ni referencias, genera 2 o 3 opciones claramente diferentes según su tema y tono, y muéstralas con fotogramas; la elección es suya.
  • Muestra, no describas: la paleta, las tipografías y el estilo de edición deben presentarse con fotogramas listos mediante video/scripts/variants.py.
  • Saltar un bloque («omitir») — solo si el usuario lo dice explícitamente. En ese caso, el perfil conserva un valor neutral predeterminado, e indícalo claramente: «más adelante puedes configurarlo — di "configura los subtítulos"».
  • No adivines nada sobre la persona. La marca, el nombre, el tema, la audiencia y el tono se obtienen únicamente de sus respuestas, no del correo de la cuenta, el nombre del sistema, el nombre de la carpeta ni el enlace al repositorio. El nombre de la cuenta en el enlace al repositorio es el autor de la plantilla, no el usuario.
  • La parte técnica no se discute en la entrevista: zonas seguras, corte sin colas recortadas, loudnorm de dos pasadas, la mecánica de punch-ins en las transiciones — no es cuestión de gusto, sino de cómo funciona el pipeline (CLAUDE.md, «Mecánica»).
  • Las claves nunca se comparten por el chat. El usuario las escribe directamente en video/.env; tú verificas el acceso mediante doctor.sh sin mostrar nada. Si alguien envía una clave en el chat, no la uses, recomiéndale revocarla y crear una nueva.
  • Todo lo que se instale con brew / pip o pese mucho, primero pregunta «qué y cuánto», luego «adelante».

Paso 0. Saludo (un solo mensaje)

Dos o tres líneas: esto es edición de videos verticales «talking head» con Claude Code + Remotion; el proyecto no tiene estilo propio — ahora lo configuraremos todo para ti: cuéntame sobre ti, comparte unos 10 reels que te gusten, elegiremos colores, tipografías y el estilo de edición (te mostraré opciones con fotogramas), y conectaremos los servicios necesarios. Pasa directamente al paso 1.

Paso 1. Entorno

cd video && ( [ -d node_modules ] || npm install ) && bash scripts/doctor.sh

Muestra el resultado en una tabla breve. Para cada elemento MISSING, sugiere el comando de la salida y, una vez que acepte, ejecútalo:

  • Skills de Remotion (obligatorio): npx -y skills add remotion-dev/skills --skill '*' --agent claude-code -y desde la raíz del proyecto.
  • ffmpeg, node, python3, yt-dlp (para referencias) — brew install … (macOS); Linux — gestor de paquetes; Windows — WSL.
  • whisper / rembg — cuando sean necesarios según las respuestas (paso 3).

Si no tiene brew, dale el enlace https://brew.sh y espera (la instalación pide contraseña, la realiza el usuario mismo).

Paso 2. Entrevista

Bloque 1 — quién eres

Marca / nombre del canal; quién aparece en cámara; de qué tratan los videos; plataformas y handles (Reels, TikTok, Shorts, Telegram…); audiencia; tono; idioma de los videos; llamado a la acción final.

Pregunta de forma abierta — deja que responda con sus palabras, aunque sea en un solo mensaje. Si ofreces opciones (para el tono o el llamado), deben ser neutrales e iguales para cualquier persona, sin un tema o nicho predefinido.

Bloque 2 — Referencias (~10 reels)

Pídele: «Comparte alrededor de 10 enlaces a reels que te gusten por su edición — de Instagram, TikTok o Shorts. Mejor si son aquellos a los que te gustaría parecerte. Con ellos entenderé tu gusto: tempo, subtítulos, gráficos, colores, tipografías». Si son menos de 5, pídele más: de 3 videos no se puede extraer un gusto general. Explícale que sin referencias tendrás que hacer más preguntas en los bloques 6–8.

Al recibir los enlaces, inicia el análisis en segundo plano inmediatamente y pasa al bloque 3:

cd video && python3 scripts/refs.py "URL1" "URL2" … > ../takes/refs.log 2>&1     # run_in_background

El script descarga los videos en takes/refs/ (no se incluye en git) y mide: duración, frecuencia de cambio de imagen, cambios en el hook, volumen, velocidad del habla, primera frase, colores brillantes (palette.png); genera NN-sheet.jpg (24 fotogramas por video) y NN-hook.jpg (primeros 3 segundos). Si algunos enlaces fallan con un mensaje de inicio de sesión requerido, consulta las opciones en SERVICES.md → «Instagram»: reinicia con COOKIES_FROM=chrome (solo con un «sí» explícito) o pídele que descargue los videos y coloque los mp4 en takes/refs/ (en ese caso, pasa las rutas en lugar de los enlaces).

Bloque 3 — Transcripción del habla

  • whisper.cpp local (recomendado en Mac): gratuito, sin conexión; brew install whisper-cpp + modelo large-v3-turbo 1.6 GB.
  • ElevenLabs Scribe: de pago (créditos), no requiere instalación, funciona en cualquier sistema; necesita una clave (bloque 4).

Bloque 4 — Servicios (un mensaje por servicio)

No preguntes con un solo mensaje «¿qué conectamos?». Revisa los servicios uno por uno — un mensaje por servicio: qué aporta a la edición (1–2 líneas con un ejemplo), cuánto cuesta, qué necesita el usuario y cuánto tiempo lleva. Pregunta: «¿lo conectamos ahora / más tarde / no lo necesito?».

ServicioQué aporta a la ediciónAccesoTiempo
ElevenLabsTranscripción Scribe; acentos de sonido según tu gusto; locuciónClave API~3 min
HiggsfieldBreves inserciones de video (B-roll), cuando hablas de algo que se puede mostrarInicio de sesión vía navegador~2 min + después de reiniciar
21st.devComponentes React listos como base para nuevos gráficosClave API~3 min
BufferBorradores de publicaciones en Reels / TikTok / ShortsInicio de sesión vía navegador + canales en Buffer~5 min

Orden: ElevenLabs → Higgsfield → 21st.dev → Buffer. Si en el bloque 3 se eligió Scribe, ElevenLabs es obligatorio; dímelo así. «Más tarde» y «no lo necesito» son respuestas válidas.

Para cada servicio al que respondan «ahora», guíalos a través de la sección correspondiente en SERVICES.md: enlaces y pasos con tus palabras, espera a que digan «listo», configura tu parte y verifica:

  • Claves (ElevenLabs, 21st.dev): si no existe video/.env, haz cp video/.env.example video/.env; el usuario escribe la clave él mismo (open -e video/.env). Verifica con bash video/scripts/doctor.sh, sección access. Si se rechaza, probablemente se copió incompleta o sin los permisos necesarios; que cree una nueva.
  • 21st.dev: después de verificar la clave, añade el servidor localmente (la clave se lee desde .env directamente en el shell):
    cd video && set -a && . ./.env && set +a && cd .. && claude mcp add --transport http 21st https://21st.dev/api/mcp --header "x-api-key: $TWENTYFIRST_API_KEY" --scope local
    
    Si claude no está en PATH, dale este comando al usuario para que lo ejecute en la terminal.
  • OAuth (Higgsfield, Buffer, opcionalmente ElevenLabs MCP): añade los servidores seleccionados al archivo .mcp.json raíz:
    {
      "mcpServers": {
        "higgsfield": { "type": "http", "url": "https://mcp.higgsfield.ai/mcp" },
        "buffer": { "type": "http", "url": "https://mcp.buffer.com/mcp" },
        "elevenlabs": { "type": "http", "url": "https://api.elevenlabs.io/v1/mcp" }
      }
    }
    
    Inicio de sesión vía navegador — después de reiniciar Claude Code (/mcp → servidor → Authenticate): díselo ahora y recuérdalo en el paso 5. Para Buffer, pídele que conecte los canales de antemano en Buffer (Instagram — cuenta profesional).

Marca los servicios conectados en la sección integrations. Si te quedas atascado en un servicio durante 15+ minutos, sugiere posponerlo: «lo conectamos más tarde — di "conecta Buffer"».

Bloque 5 — Lo que te gusta (según las referencias)

Espera a que termine el análisis (ps -axo command | grep "[r]efs.py"), lee takes/refs/refs.json, mira cada NN-hook.jpg, NN-sheet.jpg y palette.png. Por cada video, anota lo que los números no ven: subtítulos (ubicación, tamaño, mayúsculas/minúsculas, negrita, color, resaltado de palabras, fondo), gráficos (tarjetas y su apariencia, stickers, capturas de pantalla, B-roll, emojis), tamaño de plano y punch-ins, porcentaje de rostro en pantalla, paleta de gráficos, tipografías, qué hay en el hook (texto-póster, pregunta, acción), final.

Resume en un «perfil de gusto»: 5–7 patrones que aparecen en al menos la mitad de los videos, con números (medianas de refs.py). Muéstralo en un solo mensaje y pregunta: «¿esto va contigo? ¿qué de esto quieres en tus videos y qué no?». Lo que acepte se convertirá en sugerencias para los bloques 6–8 — allí mostrarás sus opciones junto a otras alternativas, no las aplicarás en silencio. Lo que no sea configurable (stickers emoji, pantalla verde…) se registra como deseo en el perfil.

Bloque 6 — Paleta (2–3 mensajes)

6.1 Preguntas — un solo mensaje, en texto abierto:

  • ¿Tienes colores de marca: logotipo, sitio web, diseño del canal, portadas? Comparte el hex, un enlace al sitio web o coloca el logotipo / captura de pantalla en takes/brand/.
  • ¿Qué debe destacar en color en los videos: cifras, palabras clave, llamados a la acción?
  • ¿Qué sensación quieres transmitir: seria, cálida, vibrante, tranquila?
  • ¿Qué colores definitivamente no quieres?

Si envía una imagen, extrae los colores principales:

python3 -c "
from PIL import Image; import sys
im = Image.open(sys.argv[1]).convert('RGB').resize((200, 200)).quantize(6)
pal = im.getpalette(); cnt = sorted(im.getcolors(), reverse=True)
print([('#%02X%02X%02X' % tuple(pal[i*3:i*3+3]), round(100*n/40000)) for n, i in cnt])
" takes/brand/logo.png

Si envía un enlace al sitio web, ábrelo y encuentra los colores principales (logotipo, botones, variables CSS).

6.2 Candidatos — 2–3 paletas con cuatro roles: dark (tarjetas, pantallas oscuras), light (texto), accent (resaltado), pain (tarjeta «esto no», si es necesario):

  • de las referencias — recurring_colours en refs.json y palette.png; verifica con los storyboards que el color sea de gráficos o texto, no de una pared, un objeto en escena o la piel;
  • de los colores de marca, si existen;
  • según las respuestas 6.1 — la sensación y qué destacar.

Legibilidad (técnica, no gusto): el texto sobre la tarjeta y sobre el metraje debe leerse bien — verifica el contraste de cada candidato (light sobre dark ≥ 7:1, accent sobre dark ≥ 3:1); si un candidato no cumple, díselo y sugiere el más cercano que sí lo haga:

python3 -c "
import sys
def L(h):
    c=[int(h[i:i+2],16)/255 for i in (1,3,5)]
    c=[x/12.92 if x<=0.03928 else ((x+0.055)/1.055)**2.4 for x in c]
    return 0.2126*c[0]+0.7152*c[1]+0.0722*c[2]
a,b=sorted([L(sys.argv[1]),L(sys.argv[2])]); print(round((b+0.05)/(a+0.05),1))
" '#FFFFFF' '#141414'

6.3 Muestra con fotogramas:

cd video && python3 scripts/variants.py out/palette-options.png 70,368 \
  '{"label":"A","colors":{"dark":"#…","light":"#…","accent":"#…","pain":"#…"}}' \
  '{"label":"B","colors":{…}}' '{"label":"C","colors":{…}}'

Muestra la hoja (SendUserFile), etiqueta: «A — de tus referencias, B — del logotipo, C — según la sensación». Correcciones («A, pero el acento más oscuro») — nueva ejecución. Lo elegido se guarda en colors.

Bloque 7 — Tipografías (2–3 mensajes)

Dos tipografías: texto (subtítulos y tarjetas, pesos 500 / 600 / 700) y póster (título al inicio del video, si lo hay). Ambas deben ser compatibles con el alfabeto del idioma de los videos.

7.1 Preguntas — un solo mensaje: ¿tienes tipografías de marca (nombres o archivos en takes/brand/)?; ¿qué carácter buscas: serio, amigable, tecnológico, editorial?; ¿los subtítulos ligeros o densos?

Si hubo bloque 2, mira los subtítulos y títulos en los storyboards y di lo que ves: tipo (grotesco geométrico, neo-grotesco, estrecho, redondeado, con serifas), peso, mayúsculas/minúsculas. No adivines el nombre exacto por la imagen — busca una tipografía libre similar.

7.2 Candidatos — 2–3 pares «texto + póster» de @fontsource con el alfabeto necesario, de diferentes estilos según sus respuestas y referencias. Para ruso, verifica el cirílico; Bebas Neue solo es latina. Si es una tipografía de marca comprada, colócala en video/src/fonts/ + @font-face con font-display: block manualmente; recuerda la licencia si el repositorio es público.

7.3 Muestra con fotogramas:

cd video && npm i @fontsource/<a> @fontsource/<b>                  # candidatos
ls node_modules/@fontsource/<a>/ | grep -c cyrillic                # para ru > 0
ls node_modules/@fontsource/<a>/ | grep -E '^[0-9]+\.css$'         # pesos disponibles
grep -m1 font-family node_modules/@fontsource/<a>/400.css          # nombre exacto de la familia

Añade los imports de los pesos candidatos en video/src/index.css (@import "@fontsource/<a>/600.css"; …), luego:

python3 scripts/variants.py out/font-options.png 70,368 \
  '{"label":"A","fonts":{"text":"…","poster":"…","posterWeight":700}}' '{"label":"B","fonts":{…}}'

Muestra, etiqueta. Después de elegir, deja en index.css solo los imports seleccionados y elimina los paquetes sobrantes (npm un …).

Bloque 8 — Estilo de edición (un mensaje por tema)

Cuatro temas, cada uno en un mensaje separado: pregunta, lo que se ve en las referencias («en 7 de cada 10, los subtítulos están centrados y grandes»), luego 2–3 opciones con fotogramas mediante variants.py (claves style.*, fotogramas 70,270,368). Sin etiquetas «recomiendo».

8.1 Subtítulos (style.captions):

  • ubicación: cycle — las frases se mueven por el fotograma (arriba-izquierda → arriba-derecha → abajo); rail — siempre abajo; center — centrado;
  • tamaño size: [palabra normal, resaltada] en px (≈ 48 pequeño, 60 mediano, 76 grande);
  • peso weight (500–800); mayúsculas/minúsculas case: lower / asis / upper;
  • resaltado highlight: color (palabras clave con el color de acento) / size (más grande) / both / none;
  • fondo box: true — tarjeta debajo de la línea, false — sombra.

8.2 Gráficos:

  • tarjetas style.cards: glass (vidrio semitransparente) / solid (tarjeta sólida) / none; con qué frecuencia — palabras en editing-taste.md §3;
  • stickers-pictogramas en pausas style.stickers: true / false;
  • póster-título detrás de la cabeza al inicio style.poster: enabled, mayúsculas/minúsculas case (upper / asis), subtítulo pequeño kicker. Si está activado, necesita rembg (~30 min por video en segundo plano, modelo ~1 GB una vez);
  • B-roll (si Higgsfield está conectado): si se necesita, cuánto — palabras en brand-kit.md §5.

8.3 Movimiento e imagen:

  • tempo de edición style.editRate: slow (sin prisas, mayor duración de tomas) / rhythmic (al ritmo de la música/habla) / fast (rápido, cortes frecuentes);
  • punch-ins style.punchIns: hacia dónde y cuándo (énfasis en la palabra, reacción, cambio de tema); frequency: rare (solo en momentos clave) / moderate (con regularidad) / often (casi en cada oración);
  • transiciones style.transitions: cut (corte seco) / crossfade (fundido cruzado) / swipe (deslizamiento);
  • estabilización style.stabilization: off / auto (estabilización suave) / cinematic (movimiento de cámara intencional);
  • gradación de color style.grade: flat (apenas corrección) / neutral (colores naturales) / warm (tonos cálidos) / vintage (película retro);

8.4 Sonido:

  • música de fondo style.music: no / generative (generada por IA, estilo que se adapta) / library (biblioteca de música libre de derechos); volumen volume respecto al habla: quiet / moderate / loud;
  • efectos de sonido style.soundEffects: no / subtle (solo acentos clave) / generous (frecuentes, como transiciones y énfasis);
  • nivel de habla style.voiceLevel: natural (sin procesamiento) / radio (compresión ligera) / podcast (compresión fuerte y limitación);

Paso 3. Configuración del perfil

Después de los bloques 6–8, escribe los archivos de configuración.

harness.config.json

{
  "configured": true,
  "colors": {
    "dark": "#…",
    "light": "#…",
    "accent": "#…",
    "pain": "#…"
  },
  "fonts": {
    "text": "…",
    "poster": "…",
    "posterWeight": 700
  },
  "style": {
    "captions": {
      "location": "center",
      "size": [60, 76],
      "weight": 700,
      "case": "upper",
      "highlight": "color",
      "box": false
    },
    "cards": "glass",
    "stickers": false,
    "poster": {
      "enabled": true,
      "case": "upper",
      "kicker": true
    },
    "editRate": "rhythmic",
    "punchIns": {
      "frequency": "moderate",
      "direction": "center"
    },
    "transitions": "cut",
    "stabilization": "auto",
    "grade": "neutral",
    "music": {
      "style": "generative",
      "volume": "moderate"
    },
    "soundEffects": "subtle",
    "voiceLevel": "natural"
  },
  "integrations": {
    "elevenlabs": true,
    "higgsfield": false,
    "21st": true,
    "buffer": false
  }
}

brand-kit.md

De los bloques 1, 2, 5:

  • Nombre de la marca, nombre del canal (si hay).
  • Tema, descripción de contenido (2–3 oraciones del bloque 1).
  • Imagen del presentador: quién, tono (bloque 1).
  • Audiencia: plataformas, datos demográficos (bloque 1).
  • Llamado a la acción (bloque 1).
  • Ejemplos de estilo visual — enlaces a los 10 referencias (bloque 2).
  • Elementos visuales característicos — tarjetas, stickers, emojis, animaciones (bloque 5).
  • Logotipo (si está en takes/brand/).

editing-taste.md

De los bloques 5, 6, 7, 8:

  • §1. Tempo y edición (bloques 5, 8.3).
  • §2. Subtítulos (bloque 8.1).
  • §3. Gráficos y tarjetas (bloque 8.2).
  • §4. Movimiento dentro del fotograma (punch-ins, transiciones; bloques 8.3, 8.4).
  • §5. Sonido y música (bloque 8.4).
  • §6. Color e iluminación (bloque 6).
  • §7. Paleta de referencia (del bloque 5, colores principales).

exemplars.md

  • Referencias: enlaces; NN-sheet.jpg, NN-hook.jpg; perfil de gusto (bloques 2, 5). Si no hay referencias, no hay archivo.

Paso 4. Finalización

Di: «La configuración está lista. Ahora puedes pedir crear un video — di "genera un video sobre [tema]"». Recomienda después de salir de la sesión volver a ejecutar harness, ya que el perfil se guarda en archivos markdown que permanecen.

Pregunta si quiere probar inmediatamente la generación de un video de prueba con las configuraciones (sin B-roll ni servicios):

cd video && npx remotion render src/index.ts TestVideo out/test.mp4

Si tiene rembg instalado (si eligió el póster), el primer video tardará ~30 minutos en procesarlo (se almacena en caché para los siguientes).

Pregunta si necesita ayuda para conectar canales en Buffer (si estaba planeado).

Diagnóstico

Si algo sale mal durante la configuración, pide permiso para realizar un diagnóstico: bash scripts/doctor.sh --verbose. Si el problema es con un servicio específico, comprueba en video/.env y bash scripts/doctor.sh con la bandera correspondiente. Si te pide la hora o «¿y ahora qué?» — mira el paso 4.

Los errores de pipa node_modules o Remotion se solucionan más a menudo con un npm install limpio: rm -rf node_modules && npm install. Si doctor.sh no funciona (ruta del script ha cambiado), ejecútalo directamente desde la raíz del proyecto.

Después de reiniciar Claude Code, la sesión de configuración comienza de nuevo desde el paso 0 (ya que no hay memoria de la anterior). El perfil se ha escrito en archivos, así que el asistente los leerá al siguiente inicio. Si necesitas reconfigurar, di «reconfigurar».

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

Skills relacionados