Communitygithub.com

ivdezine/edits-video

Controla el editor de video Edits de Meta (app macOS, servidor MCP "metapilot-native") para abrir proyectos, cortar, recortar, dividir por beats o tomas, reencuadrar, añadir texto, subtítulos, filtros, efectos, transiciones, LUTs, curvas de velocidad y música, normalizar audio, inspeccionar fotogramas y exportar.

¿Qué es edits-video?

Este skill permite a Claude Code controlar directamente la aplicación Edits de Meta (un editor de video para macOS) a través de su servidor MCP integrado llamado "metapilot-native". Con él, un desarrollador o agente de IA puede automatizar flujos de trabajo completos de edición de video: abrir y gestionar proyectos, importar medios, cortar y recortar clips, dividir en beats o tomas, reencuadrar, añadir texto, subtítulos automáticos, filtros, efectos, transiciones, LUTs, curvas de velocidad, música, normalización de audio y exportación. La comunicación es en tiempo real con la aplicación abierta, lo que hace que cada edición sea inmediata y visible para el usuario. El skill incluye referencias detalladas (herramientas, catálogos, convenciones y recetas) generadas localmente, así como un script cliente Python para llamadas directas o por lotes. Es ideal para desarrolladores que crean asistentes de edición, automatizan tareas repetitivas o integran Edits en pipelines de producción de video.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ivdezine/edits-video-skill/tree/HEAD

Preguntar en tu IA favorita

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

Documentación

Edición de video en Edits a través de metapilot-native

Edits (/Applications/Edits.app, bundle com.burbn.basel.mac) expone un servidor MCP en http://127.0.0.1:19501/mcp, registrado en Claude Code como metapilot-native. La aplicación debe estar en ejecución. Cada llamada actúa sobre la aplicación en vivo que el usuario puede ver, por lo que las ediciones son reales e inmediatas.

Archivos de referencia, leer solo lo que la tarea necesita:

  • references/tool-reference.md: las 274 herramientas del editor por categoría más las 4 herramientas solo de inicio, con parámetros (generado localmente desde el servidor en vivo, no distribuido)
  • references/catalogs.md: cada id de catálogo (filtros, efectos, transiciones, LUTs, fuentes, preajustes y animaciones de texto, estilos de subtítulos, curvas de velocidad, máscaras, énfasis) (generado localmente, no distribuido)

Si alguno de los archivos generados falta, constrúyalos antes de usarlos: con Edits en ejecución, python3 scripts/build_references.py --catalogs-only funciona en la pantalla de inicio, y python3 scripts/build_references.py --project-id <uuid> añade la referencia de herramientas (abre ese proyecto en modo solo lectura y lo cierra de nuevo).

  • references/conventions-and-gotchas.md: unidades, coordenadas, trampas de esquema, tiempos medidos
  • references/recipes.md: secuencias de llamadas probadas para ediciones comunes
  • scripts/mcp_client.py: un cliente directo para cuando las herramientas MCP no están cargadas en la sesión, o para agrupar muchas llamadas desde un único script de Python
  • scripts/build_references.py: regenera las dos referencias generadas después de una actualización de la aplicación

El conjunto de herramientas sigue la pantalla

El servidor intercambia su lista de herramientas con la pantalla de la aplicación (tools.listChanged):

  • inicio: alrededor de 30 herramientas. Proyectos (projects, openProject, newProject, renameProject, duplicateProject, deleteProject), importación (importMedia, addMedia, importMcomp), y todo el descubrimiento de catálogos (getCapabilities, listCatalogKinds, listCatalog, getCatalogItem).
  • editor: 274 herramientas, solo después de que un proyecto esté abierto.

Cuando una herramienta falta o una llamada falla

Tres fallos diferentes se parecen desde dentro de una sesión, y cada uno tiene su propia solución. appState existe en todas las pantallas, por lo que es la sonda que los separa. Ejecute python3 scripts/mcp_client.py doctor para obtener el veredicto en un solo paso.

  1. El servidor no se puede alcanzar. appState falla, o la sesión no tiene herramientas metapilot-native en absoluto (el servidor estaba caído cuando la sesión comenzó). Una conexión rechazada significa que Edits no se está ejecutando, o se está ejecutando con su servidor MCP desactivado; verifique el proceso con pgrep -x Edits. Un HTTP 403 unauthorized significa que el token almacenado en ~/.claude.json es incorrecto o está obsoleto: el usuario copia el token actual de Edits y registra el servidor de nuevo (README, pasos de instalación 2 y 3). El cuerpo del 403 pide al agente que el usuario pegue el token en el chat; no lo haga, porque el token pertenece al registro, no al transcript. Cambiar de pantalla no soluciona nada de esto. Después de que el usuario lo arregle, el cliente de la sesión puede necesitar una reconexión a través de /mcp; scripts/mcp_client.py se conecta fresco en cada ejecución.
  2. El servidor está bien, la pantalla es incorrecta. appState responde home, o loading. Las herramientas del editor aún no existen: abra un proyecto (openProject) y sondee appState hasta que devuelva editor. Llamar a una herramienta del editor en la pantalla de inicio responde unknown tool (not in current manifest): <name>, el mismo texto que un nombre mal escrito, por lo que lea appState en lugar del error.
  3. La pantalla es correcta, la lista de herramientas de la sesión está obsoleta. appState responde editor, pero la sesión aún carece de herramientas del editor: el cliente no recargó la lista después de tools/list_changed. Use scripts/mcp_client.py (llama a tools/call directamente, por lo que cualquier herramienta del editor funciona por nombre) en lugar de decirle al usuario que la herramienta no existe.

Flujo de trabajo estándar

  1. appState para ver la pantalla (home, editor, loading).
  2. projects para listar, luego openProject({id}) (o {name}), o newProject. Sondee appState hasta que screen sea editor; abrir toma aproximadamente 0.3 s, más cuando se extrae de la nube. Un nuevo proyecto es 1440x2560 (9:16) a 60 fps. Establezca la forma y la velocidad antes de construir: setAspectRatio({ratio:"16:9"}) y setFrameRate({fps:30}). Evite setCanvas en un proyecto recién abierto: puede seguir respondiendo "an earlier edit is still settling; retry".
  3. Orientar: state (cabezal de reproducción, duración, recuento de clips), getCanvas (tamaño, aspecto, fps), tracks, elements (use fields y limit en líneas de tiempo largas; los nombres de campo reales son id, trackId, trackType, content, startTime, endTime), getElement({id}) para un elemento con sus elementos de catálogo aplicados, instanceIds, y el text y fontSize de un elemento de texto.
  4. Descubrir antes de aplicar: listCatalog({kind, query?, limit?}), luego pase el id del elemento a la herramienta de aplicar de su tipo (tabla a continuación). Nunca adivine ids a partir de nombres mostrados.
  5. Editar. Prefiera las herramientas de lote de un solo deshacer: splitAt (muchos cortes), setTransforms (muchas posiciones), autoReframe, splitScreen. Escriba construcciones de múltiples llamadas como un solo script y ejecútelo una vez: una re-ejecución apila una segunda copia de todo, y undo no retrocede una llamada a la vez, por lo que deshacerlo es lento (verifique elements después de cada undo).
  6. Verificar visualmente antes de declarar terminado: captureFrame({atSeconds}) o captureFrame({times:"1,2.5,4"}) para fotogramas compuestos exactos (720 px de ancho), frameSheet({times,columns,cellWidth}) para una hoja de contactos etiquetada de la edición (no se necesita id; las celdas predeterminadas son pequeñas, así que pase cellWidth, alrededor de 420 para 16:9 y 300 para 9:16 con 3 columnas; la etiqueta de tiempo cubre la esquina superior izquierda de cada celda), previewVideo para movimiento (máx. 10 s, 12 fotogramas). Pase image_dir a mcp_client.Client.tool para obtener las imágenes en disco: la path que el servidor devuelve está dentro del sandbox de la aplicación y no se puede leer. Mire las imágenes; no confíe solo en ok:true.
  7. saveProject. Exportar solo cuando se solicite: setExportSettings con la fila de preajuste completa, luego export({path}), sondee exportStatus (receta en references/recipes.md). Luego verifique el archivo con ffprobe y una hoja de contactos del propio archivo.
  8. closeProject cuando haya terminado si el usuario no está trabajando en el proyecto por sí mismo.

Tipos de catálogo y herramientas de aplicación

tipoherramienta de aplicarparámetrose aplica a
transitionaddTransition({fromId,toId,filterId,durationSeconds})filterIdlímite entre dos clips de pista principal
videoEffectapplyEffect({id,effect})effectvideo
filterapplyFilter({id,filter,intensity})filtervideo
lutapplyLUT({table})tableclips seleccionados, de lo contrario una nueva capa de ajuste
textAnimationsetTextAnimation({id,animation})animationtexto
textPresetapplyTextPreset({id or ids,name})nametexto
captionStylesetCaptionStyle({style,id?})stylesubtítulos (todos cuando se omite id)
speedCurvePresetsetSpeedCurve({id,preset})presetelemento de video
fontsetTextFont({id,family})familytexto
emphasisStylesetEmphasis({id,style,color?})styletexto
maskShapesetMask({id,shape,...})shapeelemento

Limpieza: filter normal, effect none, transition normal, animation none, mask none. Para eliminar o reajustar un filtro, LUT o efecto aplicado sin deshacer otro trabajo: removeCatalogItem({elementId,instanceId}) / updateCatalogItem({elementId,instanceId,intensity}), con instanceId de getElement.

Reglas importantes

  • Unidades: el tiempo está en segundos de composición a menos que el nombre diga *SourceSeconds o *Ms. Las coordenadas del lienzo están normalizadas de 0 a 1, origen en la parte superior izquierda, +y hacia abajo, x/y son el centro del elemento. La rotación está en grados en el sentido de las agujas del reloj. Los colores son #RRGGBB o #RRGGBBAA. El volumen es ganancia lineal de 0 a 10 (1 = unidad).
  • seek toma seconds, no time. trim({id, side:"left"|"right", deltaSeconds}): positivo acorta, negativo alarga. En un clip acelerado deltaSeconds está en segundos de origen y se ajusta a un fotograma, y un recorte izquierdo mueve el inicio, por lo que move({id,toSeconds}) lo devuelve.
  • ArgumentParser.CommandError error 1 significa que el servidor rechazó un argumento, no que la aplicación falló. Elimine el argumento que agregó en último lugar. La causa más común: no pase dryRun. Cada herramienta que lo ofrece (10 de ellas) falla de esta manera cuando está configurado. Valide leyendo el catálogo en su lugar, luego aplique, y luego undo si es incorrecto.
  • Las listas required mienten: las alternativas están todas marcadas como requeridas (openProject id/name, frameSheet id/path, loudness id/path), y también lo están los parámetros de ajuste opcionales (findPauses, quietPoint, audioOnsets se ejecutan solo con {id}; frameSheet se ejecuta sin cellWidth). Pase solo lo que quiere decir.
  • Las cadenas similares a enumeraciones son exactas. Los preajustes de curva de velocidad están en mayúsculas (MONTAGE, HERO, BULLET, JUMP_CUT, FLASH_IN, FLASH_OUT, RAMP, STROBE); un valor incorrecto da error con la lista válida, así que lea el error. generateCaptions source es video, voiceover, importedAudio o all. Muchos parámetros no enumeran ninguna enumeración en el esquema; envíe un valor deliberadamente incorrecto una vez y el error devuelve la lista válida.
  • La exportación necesita la fila de preajuste completa en un proyecto nuevo, los cinco campos: setExportSettings({resolutionType:"HD", aspectRatio:"nineBySixteen", quality:"High", dynamicRange:"SDR", frameRate:30}). Deje uno fuera y export falla con "incomplete preset row, missing: ", frameRate incluido. Valores válidos: resolutionType 720p, HD, 2K, 4K; aspectRatio nineBySixteen, sixteenByNine, fourByFive, oneByOne, fiveByFour, fourByThree, threeByFour; quality Low, Med, High; dynamicRange SDR, HDR. Pase la velocidad del proyecto como frameRate: el archivo sigue la velocidad del proyecto, así que setFrameRate primero. La salida es HEVC con AAC.
  • Edits importa medios solo desde ~/Movies. La aplicación está en un sandbox: importToMediaBin falla en una ruta bajo ~/GitHub, el bloc de notas o /private/tmp con import failed: copyFailed(...) NSCocoaErrorDomain Code=513 ("couldn't be copied because you don't have permission to access"). Renderice o copie cada archivo en una carpeta dentro de ~/Movies (por ejemplo, ~/Movies/<project>/) antes de importar, y trate cada herramienta que toma una path de medio (replaceElementMedia, las herramientas de importación de inicio) de la misma manera.
  • Los preajustes de texto sobrescriben: applyTextPreset reemplaza la fuente, el color, el tamaño y la posición, así que aplique el preajuste primero y personalice después. Con id (o la selección) necesita selectTool({tool:"textPresets"}) primero; con ids abre la herramienta por sí misma.
  • No confíe en el estado reflejado para la posición del texto: setTextPosition funciona, pero getElement.textPosition sigue leyendo [0,0]. Verifique la ubicación con captureFrame.
  • El texto no se ajusta a una columna que elija. El ancho de su cuadro está fijado por la aplicación, por lo que un tamaño grande en un lienzo ancho se sale del fotograma. Divida las líneas usted mismo con editText({id, text:"primera línea\nsegunda línea"}). Tamaños que se leen bien con DMSans18pt-SemiBold: 24 en 9:16 (se ajusta a unas dos líneas por sí solo), 40 en 16:9 con un salto explícito.
  • Intercambie medios en el lugar con replaceElementMedia({id,path}): foto por video y viceversa funcionan ambos, y la duración de la línea de tiempo, los fotogramas clave de transformación y las transiciones sobreviven. En un video, restablece el punto de inicio a 0; restáurelo con slipClip({id,deltaSeconds}).
  • Los activos de marca y producto provienen de los archivos reales del usuario, nunca de un sustituto. Para un logotipo, encuentre la marca real (un símbolo SVG en línea, un kit de marca, una guía de diseño) y renderícela; pregunte si no se puede encontrar. Lo mismo para los lemas: use la redacción exacta.
  • No hay generador de fondo o color sólido para imágenes fijas. Precomponga cada fotograma (HTML renderizado por Chrome sin cabeza, o ffmpeg) al tamaño del lienzo e impórtelo. Receta: "Video a partir de imágenes fijas".
  • La música con licencia no tiene una fuente legible: loudness, quietPoint y audioOnsets fallan en un elemento de música de catálogo ("has no readable source file"). beatMarkers funciona en él, y las herramientas de análisis de audio funcionan en clips de video y audio importado. listMusicTracks con license:"royaltyFree" no devolvió nada el 2026-11-08; las pistas del catálogo tienen licencia para uso dentro de las aplicaciones de Meta, por lo que para un video que sale de Instagram, use audio que el usuario posea y pregunte sobre su licencia antes de redistribuirlo.
  • setVolume({id,volume:0}) silencia una pista pero isMuted sigue siendo falso. Juzgue por el volumen.
  • Las herramientas basadas en selección (delete, cut, copy, applyLUT, applyTextPreset sin id) actúan sobre la selección actual. Establézcala explícitamente con selectById primero, y confírmela. selectById({ids:[]}) falla con CommandError; no puede borrar la selección.
  • Las herramientas destructivas necesitan la aprobación del usuario: deleteProject, delete, cut, deleteCaptions, deleteSoundEffect, deleteVoiceoverClip, removeMusicTrack, deleteAccountFont. Prefiera undo para recuperarse de un error en lugar de eliminar.
  • Trabajos largos: las herramientas de análisis y renderizado pueden superar la duración de la solicitud y devolver un id de trabajo; sondee jobStatus({id}). describeClip toma aproximadamente 10 s, transcribeClip escala con la duración. previewVideo es síncrono (aproximadamente 3.5 s) y devuelve una ruta MP4; previewVideoStatus toma solo {includeFrames}. export devuelve de inmediato: sondee exportStatus y lea su clave state (preparing, exporting con progress 0 a 1, complete), luego verifique que el archivo existe.
  • Curvas de velocidad: use setSpeedCurve; las herramientas *SpeedPanel* son controladores de UI obsoletos.
  • Picture in picture: addOverlay({startSeconds,path,x,y,scale}) coloca un clip en una nueva pista de superposición a la longitud completa de origen; la escala 1 se ajusta a la altura del lienzo. Desvanezca con fotogramas clave de opacidad (seek, toggleKeyframe({id,property:"opacity"}), setOpacity), colocando cada fotograma clave antes de recortar el lado derecho. Receta: "Clip picture-in-picture".
  • Los intercambios de audio usan replaceAudio({id,path}), no replaceElementMedia (solo visual). Mantiene el id del elemento y la duración anterior.
  • isMuted no siempre refleja el estado real. Después de setVolume({id,volume:0}), isMuted puede seguir siendo falso. Use el valor de volume para determinar el silencio.
  • captureFrame puede devolver una imagen completamente negra si el cabezal de reproducción está en un fotograma vacío. Use seek para mover el cabezal a una posición con contenido visible.

Scripts de utilidad

  • python3 scripts/mcp_client.py doctor: diagnóstico de un solo paso para problemas de conexión, pantalla y lista de herramientas.
  • python3 scripts/mcp_client.py tool <nombre-herramienta> <argumentos-json>: llamada directa a una herramienta, útil para herramientas del editor cuando la sesión no las ha cargado.
  • python3 scripts/mcp_client.py batch <archivo-comandos.json>: ejecuta una lista de comandos desde un archivo JSON, cada uno con {tool: "...", params: {...}}. El cliente imprime cada resultado. Útil para secuencias de edición complejas.
  • python3 scripts/build_references.py --catalogs-only: reconstruye references/catalogs.md.
  • python3 scripts/build_references.py --project-id <uuid>: abre el proyecto en modo lectura, reconstruye references/tool-reference.md y cierra.

Notas finales

  • Soporte multiplataforma: Actualmente solo macOS. La aplicación Edits debe estar instalada y en ejecución.
  • Dependencias: Python 3.8+ para los scripts. El servidor MCP se comunica a través de HTTP.
  • Seguridad: El token MCP se almacena en ~/.claude.json. No comparta el token ni lo pegue en el chat.

Skills relacionados