Communitygithub.com

ivdezine/edits-video

Steuere Metas Edits-Videoeditor (macOS-App, MCP-Server „metapilot-native“, Tools mit Namen mcp__metapilot-native__*), um Projekte zu öffnen, zu schneiden, zu trimmen, auf Beats oder Szenen zu splitten, umzurahmen, Text, Untertitel, Filter, Effekte, Übergänge, LUTs, Geschwindigkeitskurven und Musik hinzuzufügen, Audio zu normalisieren, Einzelbilder zu prüfen und zu exportieren. Verwende dies immer, wenn der Benutzer Edits, die Edits-App, metapilot oder metapilot-native erwähnt oder darum bittet, ein Video in Edits zu bearbeiten, zu schneiden, zu untertiteln, umzurahmen, zu colorieren oder zu exportieren.

Was ist edits-video?

Diese Fähigkeit ermöglicht es einem KI-Agenten (wie Claude Code), Metas Edits-Videoeditor (macOS) vollständig über dessen MCP-Server „metapilot-native“ zu steuern. Der Agent kann Projekte öffnen, erstellen und verwalten, Medien importieren, komplexe Bearbeitungen wie Schnitte, Trimmungen, Splits auf Beats oder Szenen, automatische Bildumrahmung und Geschwindigkeitskurven anwenden, sowie Text, Untertitel, Filter, Effekte, LUTs und Übergänge hinzufügen. Die Bearbeitung erfolgt live und sichtbar in der App. Die Fähigkeit behandelt drei Arten von Fehlern (Server nicht erreichbar, falscher Bildschirm, veraltete Werkzeugliste) und bietet ein standardisiertes Arbeitsablauf-Skript sowie Referenzdateien mit allen Werkzeugen und Katalogen. Sie unterstützt auch die Audioanalyse, das Exportieren mit vollständigen Voreinstellungen und die Überprüfung von Ergebnissen durch Einzelbilderfassung und Kontaktbögen.

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

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Videobearbeitung in Edits über metapilot-native

Edits (/Applications/Edits.app, Bundle com.burbn.basel.mac) stellt einen MCP-Server unter http://127.0.0.1:19501/mcp bereit, der in Claude Code als metapilot-native registriert ist. Die App muss ausgeführt werden. Jeder Aufruf wirkt auf die live App, die der Benutzer sieht; die Bearbeitungen sind also echt und sofort.

Referenzdateien, lies nur, was die Aufgabe benötigt:

  • references/tool-reference.md: alle 274 Editor-Werkzeuge nach Kategorie plus die 4 Home-only-Werkzeuge, mit Parametern (lokal vom laufenden Server generiert, nicht mitgeliefert)
  • references/catalogs.md: jede Katalog-ID (Filter, Effekte, Übergänge, LUTs, Schriftarten, Text- Voreinstellungen und Animationen, Untertitelstile, Geschwindigkeitskurven, Masken, Betonungen) (lokal generiert, nicht mitgeliefert)

Wenn eine der generierten Dateien fehlt, erstelle sie, bevor du dich darauf verlässt: bei laufender Edits, python3 scripts/build_references.py --catalogs-only funktioniert auf dem Startbildschirm, und python3 scripts/build_references.py --project-id <uuid> fügt die Werkzeugreferenz hinzu (es öffnet dieses Projekt im schreibgeschützten Modus und schließt es wieder).

  • references/conventions-and-gotchas.md: Einheiten, Koordinaten, Schema-Fallstricke, gemessene Zeitabläufe
  • references/recipes.md: getestete Aufrufsequenzen für übliche Bearbeitungen
  • scripts/mcp_client.py: ein direkter Client für den Fall, dass MCP-Werkzeuge nicht in der Sitzung geladen sind, oder für die Stapelverarbeitung vieler Aufrufe aus einem Python-Skript
  • scripts/build_references.py: regeneriert die beiden generierten Referenzen nach einem App-Update

Der Werkzeugsatz folgt dem Bildschirm

Der Server tauscht seine Werkzeugliste mit dem App-Bildschirm aus (tools.listChanged):

  • home: etwa 30 Werkzeuge. Projekte (projects, openProject, newProject, renameProject, duplicateProject, deleteProject), Import (importMedia, addMedia, importMcomp) und alle Katalogerkennung (getCapabilities, listCatalogKinds, listCatalog, getCatalogItem).
  • editor: 274 Werkzeuge, nur nachdem ein Projekt geöffnet ist.

Wenn ein Werkzeug fehlt oder ein Aufruf fehlschlägt

Drei verschiedene Fehler sehen innerhalb einer Sitzung gleich aus, und jeder hat seine eigene Behebung. appState existiert auf jedem Bildschirm und ist daher die Sonde, die sie trennt. Führe python3 scripts/mcp_client.py doctor aus, um das Urteil in einem Schritt zu erhalten.

  1. Der Server ist nicht erreichbar. appState selbst schlägt fehl, oder die Sitzung hat überhaupt keine metapilot-native-Werkzeuge (der Server war beim Start der Sitzung nicht verfügbar). Eine verweigerte Verbindung bedeutet, dass Edits nicht läuft oder dass der MCP-Server ausgeschaltet ist; überprüfe den Prozess mit pgrep -x Edits. Ein HTTP-403 unauthorized bedeutet, dass das in ~/.claude.json gespeicherte Token falsch oder veraltet ist: Der Benutzer kopiert das aktuelle Token aus Edits und registriert den Server erneut (README, Installationsschritte 2 und 3). Der 403-Text fordert den Agenten auf, den Benutzer zu bitten, das Token in den Chat einzufügen; tue dies nicht, weil das Token in die Registrierung gehört, nicht in das Transkript. Das Wechseln von Bildschirmen behebt keine davon. Nachdem der Benutzer es behoben hat, muss der client der Sitzung möglicherweise eine erneute Verbindung über /mcp herstellen; scripts/mcp_client.py verbindet sich bei jedem Lauf neu.
  2. Der Server ist in Ordnung, der Bildschirm ist falsch. appState antwortet home oder loading. Editor-Werkzeuge existieren noch nicht: Öffne ein Projekt (openProject) und frage appState ab, bis es editor anzeigt. Der Aufruf eines Editor-Werkzeugs auf dem Startbildschirm antwortet mit unknown tool (not in current manifest): <name>, dem gleichen Text wie bei einem falsch geschriebenen Namen; lies daher appState anstelle der Fehlermeldung.
  3. Der Bildschirm ist richtig, die Werkzeugliste der Sitzung ist veraltet. appState antwortet editor, aber die Sitzung hat noch keine Editor-Werkzeuge: Der client hat die Liste nicht nach tools/list_changed neu geladen. Verwende scripts/mcp_client.py (es ruft tools/call direkt auf, sodass jedes Editor-Werkzeug mit Namen funktioniert), anstatt dem Benutzer mitzuteilen, dass das Werkzeug nicht existiert.

Standard-Arbeitsablauf

  1. appState, um den Bildschirm zu sehen (home, editor, loading).
  2. projects zum Auflisten, dann openProject({id}) (oder {name}) oder newProject. Frage appState ab, bis screen editor ist; das Öffnen dauert etwa 0,3 s, länger, wenn es aus der Cloud zieht. Ein neues Projekt ist 1440x2560 (9:16) bei 60 fps. Stelle das Format und die Bildrate ein, bevor du aufbaust: setAspectRatio({ratio:"16:9"}) und setFrameRate({fps:30}). Vermeide setCanvas bei einem frisch geöffneten Projekt: Es kann immer noch mit "an earlier edit is still settling; retry" antworten.
  3. Orientieren: state (Abspielposition, Dauer, Clip-Anzahl), getCanvas (Größe, Seitenverhältnis, fps), tracks, elements (verwende fields und limit bei langen Zeitleisten; die tatsächlichen Feldnamen sind id, trackId, trackType, content, startTime, endTime), getElement({id}) für ein einzelnes Element mit angewandten Katalogeinträgen, instanceIds und bei einem Textelement dessen text und fontSize.
  4. Erkunden, bevor du anwendest: listCatalog({kind, query?, limit?}), dann übergib die id des Eintrags an das entsprechende Anwendungswerkzeug der Kategorie (Tabelle unten). Rate niemals IDs aus Anzeigenamen.
  5. Bearbeiten. Bevorzuge die Ein-Undo-Stapelwerkzeuge: splitAt (viele Schnitte), setTransforms (viele Positionen), autoReframe, splitScreen. Schreibe Multi-Aufruf-Builds als ein Skript und führe es einmal aus: Eine erneute Ausführung stapelt eine zweite Kopie von allem, und undo geht nicht einen Aufruf nach dem anderen zurück, also ist das Rückgängigmachen langsam (überprüfe elements nach jedem undo).
  6. Visuell überprüfen, bevor du es als erledigt erklärst: captureFrame({atSeconds}) oder captureFrame({times:"1,2.5,4"}) für exakt zusammengesetzte Einzelbilder (720 px breit), frameSheet({times,columns,cellWidth}) für einen beschrifteten Kontaktbogen der Bearbeitung (keine id erforderlich; die Standardzellen sind klein, übergib daher cellWidth, etwa 420 für 16:9 und 300 für 9:16 bei 3 Spalten; die Zeitbeschriftung bedeckt die obere linke Ecke jeder Zelle), previewVideo für Bewegung (max. 10 s, 12 Bilder). Übergib image_dir an mcp_client.Client.tool, um die Bilder auf der Festplatte zu erhalten: Den path, den der Server zurückgibt, befindet sich innerhalb der Sandbox der App und kann nicht gelesen werden. Sieh dir die Bilder an; vertraue nicht allein auf ok:true.
  7. saveProject. Exportiere nur, wenn danach gefragt wird: setExportSettings mit der vollständigen Voreinstellungszeile, dann export({path}), frage exportStatus ab (Rezept in references/recipes.md). Überprüfe dann die Datei mit ffprobe und einem Kontaktbogen aus der Datei selbst.
  8. closeProject, wenn du fertig bist, falls der Benutzer nicht selbst in dem Projekt arbeitet.

Katalogarten und Anwendungswerkzeuge

ArtAnwendungswerkzeugParameterAngewendet auf
transitionaddTransition({fromId,toId,filterId,durationSeconds})filterIdGrenze zwischen zwei Hauptspur-Clips
videoEffectapplyEffect({id,effect})effectvideo
filterapplyFilter({id,filter,intensity})filtervideo
lutapplyLUT({table})tableausgewählte Clips, andernfalls eine neue Anpassungsebene
textAnimationsetTextAnimation({id,animation})animationtext
textPresetapplyTextPreset({id or ids,name})nametext
captionStylesetCaptionStyle({style,id?})styleUntertitel (alle, wenn id weggelassen)
speedCurvePresetsetSpeedCurve({id,preset})presetVideoelement
fontsetTextFont({id,family})familytext
emphasisStylesetEmphasis({id,style,color?})styletext
maskShapesetMask({id,shape,...})shapeelement

Löschen: Filter normal, Effekt none, Übergang normal, Animation none, Maske none. Um einen angewandten Filter, eine LUT oder einen Effekt zu entfernen oder nachzujustieren, ohne andere Arbeit rückgängig zu machen: removeCatalogItem({elementId,instanceId}) / updateCatalogItem({elementId,instanceId,intensity}), mit instanceId aus getElement.

Wichtige Regeln

  • Einheiten: Zeit ist in Kompositionssekunden, es sei denn, der Name sagt *SourceSeconds oder *Ms. Leinwand- Koordinaten sind normalisiert von 0 bis 1, Ursprung oben links, +y nach unten, x/y sind die Elementmitte. Rotation ist in Grad im Uhrzeigersinn. Farben sind #RRGGBB oder #RRGGBBAA. Lautstärke ist linearer Verstärkungsfaktor 0 bis 10 (1 = Einheit).
  • seek nimmt seconds, nicht time. trim({id, side:"left"|"right", deltaSeconds}): positiv verkürzt, negativ verlängert. Bei einem beschleunigten Clip ist deltaSeconds in Quellsekunden und rastet auf ein Einzelbild ein, und ein Trimmen links verschiebt den Start, daher verschiebe mit move({id,toSeconds}) zurück.
  • ArgumentParser.CommandError error 1 bedeutet, dass der Server ein Argument abgelehnt hat, nicht dass die App fehlgeschlagen ist. Entferne das Argument, das du zuletzt hinzugefügt hast. Die häufigste Ursache: übergib nicht dryRun. Jedes Werkzeug, das es anbietet (10 davon), schlägt auf diese Weise fehl, wenn es gesetzt ist. Validiere, indem du stattdessen den Katalog liest, dann wende an, dann mache undo, wenn es falsch ist.
  • required-Listen lügen: Alternativen sind alle als erforderlich markiert (openProject id/name, frameSheet id/path, loudness id/path), und das gleiche gilt für optionale Optimierungsparameter (findPauses, quietPoint, audioOnsets laufen mit {id} allein; frameSheet läuft ohne cellWidth). Übergib nur, was du beabsichtigst.
  • Enum-ähnliche Zeichenfolgen sind exakt. Geschwindigkeitskurven-Voreinstellungen sind in Großbuchstaben (MONTAGE, HERO, BULLET, JUMP_CUT, FLASH_IN, FLASH_OUT, RAMP, STROBE); ein falscher Wert meldet einen Fehler mit der gültigen Liste, also lies die Fehlermeldung. generateCaptions source ist video, voiceover, importedAudio oder all. Viele Parameter listen kein Enum im Schema auf; sende einmal einen absichtlich falschen Wert, und der Fehler gibt die gültige Liste zurück.
  • Export benötigt die vollständige Voreinstellungszeile bei einem neuen Projekt, alle fünf Felder: setExportSettings({resolutionType:"HD", aspectRatio:"nineBySixteen", quality:"High", dynamicRange:"SDR", frameRate:30}). Lasse eines aus, und export schlägt fehl mit "incomplete preset row, missing: ", einschließlich frameRate. Gültige Werte: resolutionType 720p, HD, 2K, 4K; aspectRatio nineBySixteen, sixteenByNine, fourByFive, oneByOne, fiveByFour, fourByThree, threeByFour; quality Low, Med, High; dynamicRange SDR, HDR. Übergib die Projekt- Bildrate als frameRate: Die Datei folgt der Projekt-Bildrate, setze also zuerst setFrameRate. Die Ausgabe ist HEVC mit AAC.
  • Edits importiert Medien nur aus ~/Movies. Die App ist sandboxed: importToMediaBin schlägt bei einem Pfad unter ~/GitHub, der Zwischenablage oder /private/tmp mit import failed: copyFailed(...) NSCocoaErrorDomain Code=513 fehl ("konnte nicht kopiert werden, da Sie keine Berechtigung zum Zugriff haben"). Rendere oder kopiere jede Datei in einen Ordner unter ~/Movies (z. B. ~/Movies/<project>/), bevor du importierst, und behandle jedes Werkzeug, das einen Medien-path akzeptiert (replaceElementMedia, die Home-Import-Werkzeuge) auf die gleiche Weise.
  • Text-Voreinstellungen überschreiben: applyTextPreset ersetzt Schriftart, Farbe, Größe und Position, also wende die Voreinstellung zuerst an und passe sie danach an. Mit id (oder der Auswahl) benötigt es selectTool({tool:"textPresets"}) zuerst; mit ids öffnet es das Werkzeug selbst.
  • Vertraue nicht dem zurückgemeldeten Zustand für die Textposition: setTextPosition funktioniert, aber getElement.textPosition liest weiterhin [0,0]. Überprüfe die Platzierung mit captureFrame.
  • Text wird nicht auf eine von dir gewählte Spalte umgebrochen. Die Breite seines Rahmens wird von der App festgelegt, sodass eine große Größe auf einer breiten Leinwand aus dem Rahmen läuft. Füge Zeilenumbrüche selbst mit editText({id, text:"erste zeile\nzweite zeile"}) ein. Größen, die mit DMSans18pt-SemiBold gut lesbar sind: 24 bei 9:16 (wird von selbst auf etwa zwei Zeilen umbrochen), 40 bei 16:9 mit einem expliziten Umbruch.
  • Medien vor Ort austauschen mit replaceElementMedia({id,path}): Foto gegen Video und zurück funktionieren beide, und die Zeitleistendauer, Transformations-Keyframes und Übergänge bleiben erhalten. Bei einem Video wird der In-Punkt auf 0 zurückgesetzt; stelle ihn mit slipClip({id,deltaSeconds}) wieder her.
  • Marken- und Produkt-Assets stammen aus den echten Dateien des Benutzers, niemals aus einem Ersatz. Für ein Logo finde die tatsächliche Markierung (ein Inline-SVG-Symbol, ein Brand Kit, eine Designrichtlinie) und rendere sie; frage nach, wenn sie nicht gefunden werden kann. Gleiches gilt für Slogans: Verwende die exakte Formulierung.
  • Es gibt keinen Hintergrund- oder Vollfarb-Generator für Standbilder. Erstelle jedes Einzelbild vorab (HTML gerendert von Headless Chrome oder ffmpeg) in der Leinwandgröße und importiere dieses. Rezept: "Video aus Standbildern".
  • Lizenzierte Musik hat keine lesbare Quelle: loudness, quietPoint und audioOnsets schlagen bei einem Katalog-Musikelement fehl ("has no readable source file"). beatMarkers funktioniert damit, und die Audio- Analysewerkzeuge funktionieren bei Videoclips und importiertem Audio. listMusicTracks mit license:"royaltyFree" hat am 2026-11-08 nichts zurückgegeben; Katalog-Tracks sind für die Verwendung innerhalb von Meta-Apps lizenziert, also für ein Video, das Instagram verlässt, verwende Audio, das der Benutzer besitzt, und frage nach seiner Lizenz, bevor es weiterverteilt wird.
  • setVolume({id,volume:0}) stummschaltet eine Spur, aber isMuted bleibt false. Beurteile nach der Lautstärke.
  • Auswahlbasierte Werkzeuge (delete, cut, copy, applyLUT, applyTextPreset ohne id) wirken auf die aktuelle Auswahl. Setze sie zuerst explizit mit selectById, und bestätige sie. selectById({ids:[]}) schlägt fehl mit CommandError; es kann die Auswahl nicht löschen.
  • Zerstörende Werkzeuge benötigen die Zustimmung des Benutzers: deleteProject, delete, cut, deleteCaptions, deleteSoundEffect, deleteVoiceoverClip, removeMusicTrack, deleteAccountFont. Bevorzuge undo, um einen Fehler rückgängig zu machen, anstatt zu löschen.
  • Lange Aufgaben: Analyse- und Rendering-Werkzeuge können die Anfrage überdauern und eine Job-ID zurückgeben; frage jobStatus({id}) ab. describeClip dauert etwa 10 s, transcribeClip skaliert mit der Länge. previewVideo ist synchron (etwa 3,5 s) und gibt einen MP4-Pfad zurück; previewVideoStatus akzeptiert nur {includeFrames}. export kehrt sofort zurück: frage exportStatus ab und lese seinen state-Schlüssel (preparing, exporting mit progress 0 bis 1, complete), dann überprüfe, ob die Datei existiert.
  • Geschwindigkeitskurven: Verwende setSpeedCurve; die *SpeedPanel*-Werkzeuge sind veraltete UI-Treiber.
  • Bild im Bild: addOverlay({startSeconds,path,x,y,scale}) platziert einen Clip auf einer neuen Overlay-Spur in voller Quelllänge; Skalierung 1 passt die Leinwandhöhe an. Blende ihn mit Opazitäts- Keyframes ein (seek, toggleKeyframe({id,property:"opacity"}), setOpacity), platziere jeden Keyframe, bevor du die rechte Seite trimmst. Rezept: "Bild-im-Bild-Clip".
  • Audio-Austausche verwenden replaceAudio({id,path}), nicht replaceElementMedia (nur visuell). Es behält die Element-ID und die alte Dauer bei.

Verwandte Skills