Video de recorrido del repositorio
El objetivo es tener un video que un compañero de equipo pueda ver para entender un repositorio: para qué sirve, cómo encajan sus partes y cada función ejecutada de verdad, incluyendo lo que está roto hoy. Aquí se mezclan dos trabajos, y deben hacerse en este orden:
- Prueba el repositorio de verdad. Cada comando que se muestra en el video realmente se ha ejecutado y se ha leído su salida.
- Grábalo como una historia. Los capítulos siguen la forma del sistema, y cada uno está narrado.
Un video que solo muestra comandos que funcionan engaña al equipo. Los fallos que encuentras mientras pruebas suelen ser la parte más valiosa del video, así que dales su propio capítulo de cierre.
Estructura de salida
Trabaja en una carpeta fuera del repositorio. El usuario la elige; si no lo hace, usa una hermana como <parent-of-repo>/video/, porque una ruta raíz como /video suele ser de solo lectura en macOS.
video/
├── <nombre>-walkthrough.mp4 # video completo: capítulos + pista de subtítulos mov_text
├── <nombre>-walkthrough.srt # misma narración, también útil como transcripción
├── chapters/NN-slug.mp4 # un archivo por capítulo
├── README.md # índice de capítulos con tiempos de inicio, cómo regrabar
├── src/ # engine.py, make_readme.py, script.py (+ helpers)
├── work/ # clon(es) temporales del repositorio: aquí se ejecutan todos los comandos
└── build/ # archivos intermedios (voz por segmento, fotogramas, clips)
Nunca ejecutes los comandos de la demo en la copia de trabajo del usuario. Clónalo en work/ (git clone <repo> work/<nombre>) para que el video pueda romper cosas a propósito (manifiestos incorrectos, fallos inyectados) y restablecer con git checkout . && git clean -fd. Si el checkout del usuario tiene cambios sin commit, menciónalos y déjalos como están.
Paso 1: Verifica las herramientas e informa al usuario de lo que falta
which vhs ffmpeg ffprobe jq; python3 -c "import PIL; print(PIL.__version__)"; say -v '?' | head -3
Si falta algo, dile al usuario qué instalar y por qué, antes de instalarlo (brew install vhs ffmpeg jq). Para Pillow, no toques el Python del sistema. Ejecuta el motor con uv en su lugar: uv run --no-project --with pillow python engine.py .... Envuélvelo en una función de shell (py() { uv run --no-project --with pillow python "$@"; }), porque una variable que contenga el comando no se expandirá como una unidad. Lo mismo aplica para cualquier cosa que necesite el repositorio, como Docker en ejecución, un stack de simulador o credenciales. Pídele al usuario esas cosas y nunca inventes un secreto.
Una voz premium (Ajustes del Sistema → Accesibilidad → Contenido Hablado, ej. "Ava (Premium)") suena mucho mejor que la Samantha por defecto. Ofrécela, pero no te detengas por ello; VOICE=... engine.py --force permite cambiar la voz más tarde.
Paso 2: Entiende y prueba el repositorio antes de escribir una palabra de narración
Lee el README, los docs o ADRs, los puntos de entrada de la CLI (--help de cada subcomando), los marcadores de pruebas, el Makefile y la configuración de CI. Construye un inventario de cada función que un usuario puede ejercitar: cada subcomando de la CLI, cada suite de pruebas, cada integración, cada modo de fallo contra el que el código se defiende.
Luego ejecuta todo en work/ y anota:
- los comandos exactos que muestran bien cada característica, con salida corta (usa
jq,head,tail,cut -c1-160) - lo que falla, y si es un error real o solo tu entorno (ruta por defecto incorrecta, variable de entorno faltante). Arregla los problemas de entorno en el clon o con variables de entorno, y haz que ese arreglo sea visible en el video, porque el equipo también se lo encontrará.
- cómo romper cada regla de seguridad a propósito (un fixture, un
sedsobre una copia), para que el video pueda mostrar la regla activándose
Estas notas se convierten en el capítulo de hallazgos. Mantenlas como una lista de elementos numerados y concretos.
Paso 3: Planifica los capítulos
Sigue el propio pipeline del sistema, no el listado de carpetas. Una estructura que ha funcionado bien:
| # | Capítulo | Contenido |
|---|---|---|
| 00 | Bienvenida | tarjeta de título, luego una diapositiva de "lo que verás" |
| 01 | Panorama general | un propósito en una oración, el pipeline como cajas y flechas, una escena de terminal con la estructura del repositorio |
| 02 | Configuración | instalación, la CLI agrupada por propósito, la suite de pruebas rápida |
| … | un capítulo por etapa del pipeline | comandos reales, más una escena de "romperlo a propósito" por regla |
| … | en vivo / integración | los servicios reales de respaldo, de extremo a extremo |
| N-1 | Contratos / traspaso | de qué dependen otros equipos |
| N | Hallazgos y siguientes pasos | la lista numerada de hallazgos, luego qué hacer a continuación |
Apunta a 1–3 minutos por capítulo y 15–25 minutos en total. Un capítulo es una idea; un segmento es una pantalla más una narración. Muestra al usuario este esquema (títulos de capítulo y una línea cada uno) antes de grabar.
Paso 4: Escribe src/script.py
Copia los scripts incluidos en la carpeta del video:
mkdir -p video/src && cp <skill-dir>/scripts/{engine.py,make_readme.py,agent.jq} video/src/
cp <skill-dir>/scripts/script_template.py video/src/script.py
script.py contiene todas las palabras y todos los comandos. engine.py los convierte en video. Lee references/script-format.md para el esquema completo de segmentos, los diseños de diapositivas y el estilo de narración. scripts/script_template.py muestra cada tipo de segmento con un ejemplo funcional; construye el resto de los capítulos con la misma forma (el Paso 3 da el esquema de capítulos).
Reglas de narración más importantes:
- Escribe para el oído: frases cortas, sin markdown, y deletrea los acrónimos que la voz pronuncie mal (
"M C P","C L I"), o agrégalos aSPOKENenscript.py. - Di lo que el espectador debe mirar ("Mira los skills: cero"). La voz y la imagen deben coincidir, así que si cambias la salida de un comando (un conteo, un factor de velocidad), arregla también la frase.
- Los subtítulos (la barra inferior de una escena de terminal) son una línea que indica el punto, con
códigoentre comillas invertidas.
Paso 5: Simulación en seco, luego graba
cd video/src # `py` = Python con Pillow (ver Paso 1)
py engine.py --dry # ejecuta cada comando de terminal en bash simple e imprime la salida, sin video
py engine.py --dry --only 04 # un capítulo
py engine.py --only 04 # graba un capítulo (retroalimentación rápida sobre el aspecto)
py engine.py # todo lo que falta o cambió, luego ensambla el video completo
py engine.py --only 07 --reuse-terms # conserva los clips VHS, regraba solo la voz y los fotogramas (arreglos de narración)
py make_readme.py # escribe README.md con el índice de capítulos
Haz siempre una simulación en seco primero. Son minutos en lugar de una hora, y detecta cualquier comando que dé error, se cuelgue o imprima demasiado. Graba un capítulo primero y mira los fotogramas antes de la compilación completa:
ffmpeg -v error -ss 20 -i chapters/04-*.mp4 -frames:v 1 build/check.png # luego lee el PNG
Una compilación completa lleva mucho tiempo (unos 40 minutos para 21 minutos de video). Ejecútala en segundo plano y espera su notificación de finalización en lugar de consultar periódicamente. Los capítulos se guardan en caché mediante un hash de su script, por lo que volver a ejecutar solo reconstruye lo que ha cambiado.
Paso 6: Verifica y entrega
ffprobe -v error -show_chapters -show_streams -of compact video/<nombre>-walkthrough.mp4 | head -40
Verifica lo siguiente:
- la duración
- 1920×1080 h264, aac y una secuencia de subtítulos mov_text
- un marcador de capítulo por capítulo
- fotogramas de muestra de algunos capítulos: sin texto que desborde los cuadros, subtítulos dentro de dos líneas
Luego dile al usuario las rutas exactas del MP4, la carpeta chapters/, el SRT y el README. Añade cómo abrirlo (open video/<nombre>-walkthrough.mp4; QuickTime o VLC muestran los menús de capítulos y subtítulos) y la lista de hallazgos. Menciona cualquier contenedor o servicio que hayas dejado ejecutándose, y cómo detenerlos.
Problemas ya resueltos (tenlos en cuenta al editar el motor)
- Shells en entorno aislado: vhs, Docker, las cachés de
uvysaya menudo fallan bajo un entorno aislado ("Operation not permitted", errores de socket de Docker). Esos comandos deben ejecutarse fuera de él.opentambién está bloqueado, así que dale al usuario el comando para que lo ejecute él mismo. - Caída de fotogramas en VHS: los 50 fps por defecto pierden fotogramas en escenas largas. El motor usa
Set Framerate 15. Outputde VHS debe ser un nombre de archivo simple. Ejecutavhsconcwdestablecido en la carpeta de salida.- Las cadenas de VHS no tienen escapes. El escape de
json.dumpsrompe las secuencias de escape de PS1. Usaq()en el motor, que elige un delimitador",'o`que el texto no contenga. Waitse cuelga si el patrón no coincide con el prompt. El motor establece un PS1 que termina en$y usaWaitPattern /[>$]$/. Los comandos que imprimen una línea final terminada en$o>pueden terminar una espera antes de tiempo, así que añade unpauseahí.- Escenas de larga duración (un agente de IA, una ejecución de pipeline): establece
"speedup": Trueen el segmento. El motor acelera el clip aproximadamente hasta la duración de la narración y estampasped up ×N.Nen el encabezado, así que di que está acelerado. - Desbordamiento de texto en diapositivas:
wrap()mide los fragmentos de código en la fuente monoespaciada. Mantén los cuerpos de los cuadros cortos y divide las rutas largas en dos líneas. - Bucles de espera: un bucle
pgrep -f <patrón>coincide consigo mismo. Espera en su lugar un PID o un archivo. - Hooks previos (
"before": [...]en un capítulo) preparan el estado: reinician un contenedor de BD, disparan un pipeline, inyectan un fallo. Pon el deshacer (restablecer, desinjectar) en el mismo capítulo, para que una reconstrucción de un capítulo nunca deje la plataforma rota. - Secretos necesarios para la demo van en un archivo ignorado por git en el clon (por ejemplo
dev-vault.env). Nunca muestres sus valores en pantalla, y nunca los hagas commit.
Mostrando un agente de IA en acción (opcional)
Si el repositorio construye o configura un agente, la escena más potente es el agente diagnosticando un fallo real e inyectado. Ejecútalo sin interfaz gráfica con salida stream-json, y formatea el stream con el agent.jq incluido (una línea por llamada a herramienta, luego la respuesta):
claude -p "<pregunta>" --output-format stream-json --verbose | jq -rj -f /ruta/a/video/src/agent.jq
Marca ese segmento con "speedup": True, y restablece el fallo después en el mismo capítulo.