Communitygithub.com

mikey-relevanceai/record-demo

Nimm ein menschlich getaktetes MP4-Walkthrough einer UI-Änderung auf, um es an einen PR anzuhängen. Funktioniert mit Web-Apps über headless Playwright und Electron-Desktop-Apps über echte Display- oder Fensteraufnahme. Enthält die Regeln für die Durchführung einer Aufnahme; die Mechanismen für die einzelnen Oberflächen finden sich in reference/.

Was ist record-demo?

Dieses Skill ermöglicht es einem KI-Agenten, ein menschenähnliches Walkthrough-Video einer UI-Änderung aufzunehmen und an einen Pull Request anzuhängen. Es simuliert menschliches Verhalten durch geschwungene Cursor-Pfade, Tastenanschlag-für-Tastenanschlag-Tippen und bewusste Pausen – im Gegensatz zu maschinellen, ruckartigen UI-Automationen. Der Skill unterstützt zwei Oberflächen: Web-Apps via headless Chromium unter Playwright (mit einem im DOM gezeichneten Cursor) und Electron-Desktop-Apps, die eine echte Fenster- oder Bildschirmaufnahme erfordern. Die ausführlichen Regeln in der SKILL.md stellen sicher, dass Aufnahmen reproduzierbar, fehlerresistent und qualitativ hochwertig sind – dazu gehören Probenläufe, das Überprüfen von Steuerelement-Namen, asynchrones Warten statt fester Timeouts, sowie die Überprüfung des Outputs mit ffprobe. Das Skill integriert sich nahtlos in CLI-Workflows und kann Videos direkt mit `gh pr comment --attach` an GitHub PRs anhängen.

Funktioniert mit✓Claude Code✓Codex CLI✓Cursor
npx skills add https://github.com/mikey-relevanceai/record-demo/tree/main/skills/record-demo

In Ihrer bevorzugten KI fragen

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

Vorschau

Aus dem Skill-README

alt

Dokumentation

Demo aufnehmen

Nimmt ein Walkthrough auf, das wie eine Person aussieht, die die App benutzt – geschwungene Cursor-Pfade, Tastenanschlag-für-Tastenanschlag-Tippen, bewusste Pausen – anstatt wie eine Maschine, die durch die UI teleportiert.

Die folgenden Regeln gelten für jede Aufnahme, auf jeder Oberfläche. Sie stehen hier und nicht in den Plattform-Referenzen, weil jede Regel schon einmal gebrochen wurde und einen Take gekostet hat, und weil eine Regel, die nur neben einem Mechanismus steht, eine Regel ist, die die nächste Person nicht liest.

Wähle die Oberfläche

  • Die Web-App – reference/web.md. Headless Chromium unter Playwright mit einem DOM-Cursor, der in die Seite gezeichnet wird. Nichts erreicht den Bildschirm des Bedieners. Bevorzuge dies immer, wenn die Änderung in einem Browser sichtbar ist.
  • Die Desktop-App – reference/desktop.md. Erforderlich, wenn die Demo die echte Electron-Shell benötigt: native Menüs, Datei-Dialoge, Tray, mehrere Fenster oder alles außerhalb des Renderers. Linux hat einen gebündelten Runner; macOS zeichnet ein einzelnes Fenster per ID auf und hat noch keinen Runner.

Wenn die Änderung auf beiden sichtbar ist, nimm die Web-App auf.

Eingaben

Lege diese vor dem ersten Take fest. Lies sie aus dem Projekt, wo du kannst (aus dessen README, package.json-Skripten, dem Electron-Hauptprozess); frage den Benutzer nach allem, was du nicht finden kannst, anstatt zu raten.

  • Web: die URL der laufenden App, die dem Rekorder als PR_RECORDER_BASE_URL übergeben wird (z.B. http://localhost:3000). Die App muss bereits aus dem Checkout laufen, das die Änderung enthält, einschließlich uncommitteter Änderungen – ein frischer Checkout desselben Branches hat sie nicht, und git weigert sich, einen Branch zweimal auszuchecken. Sie muss außerdem in dem Zustand sein, den die Demo benötigt. Wenn der Ablauf einen angemeldeten Benutzer oder vorbereitete Daten erfordert, ist das die Aufgabe des Projekts, dies bereitzustellen, nicht die des Rekorders – aber bestätige es vor dem Aufnahmestart, sonst bekommst du einen Take eines Anmeldebildschirms.
  • Desktop:
    • DEMO_APP_DIR – das Verzeichnis, in dem der Startbefehl der App ausgeführt wird.
    • DEMO_WINDOW_TITLE – der genaue Titel des Hauptfensters, verwendet, um sowohl das X11-Fenster als auch die Renderer-Seite zu finden.
    • DEMO_LAUNCH_CMD – optional. Ein Shell-Befehl, der die App mit Remote-Debugging auf {port} startet. Der Standardwert pnpm dev --remoteDebuggingPort {port} --noSandbox passt zu electron-vite.

Wo das Skill lebt

<skill-dir> in dieser Dokumentation bedeutet das Verzeichnis, aus dem diese SKILL.md geladen wurde. In Claude Code ist es ${CLAUDE_SKILL_DIR}, was sowohl für Projekt-, persönliche als auch Plugin-Installationen funktioniert. Andernorts verwende den Pfad, aus dem das Skill geladen wurde – für Codex ein Ordner .agents/skills/record-demo im Repository oder ~/.agents/skills/record-demo. Löse es einmal auf und verwende den absoluten Pfad; die Skripte gehen nie davon aus, wo das Skill installiert ist.

Probe vor dem Take, der zählt

Führe den gesamten Ablauf von Anfang bis Ende durch, bevor du den Take aufnimmst, den du ausliefern wirst. Eine Demo wird entdeckt, nicht geschrieben: Steuerelement-Namen sind nicht das, was du erwartest, ein Button tut etwas anderes, als sein Name sagt, und eine Oberfläche braucht länger, um sich zu beruhigen, als du geschätzt hast. Das auf Kamera herauszufinden, bedeutet, dass der Zuschauer zusieht, wie du es herausfindest.

Proben sind billig und Wiederholungen sind billig. Einen Take mit einem falschen Abzweig auszuliefern oder den Reviewer zu bitten, die mittleren acht Sekunden zu ignorieren, ist das nicht.

Überprüfe zuerst die echten Steuerelement-Namen

Skripte niemals gegen ein Steuerelement schreiben, von dem du nicht bestätigt hast, dass es existiert und das tut, was sein Name vermuten lässt. Lade die App einmal, gib die zugänglichen Namen aus und mache einen Screenshot:

const names = await page
  .getByRole("button")
  .evaluateAll((els) =>
    els.map((e) => (e.getAttribute("aria-label") || e.textContent || "").trim()).filter(Boolean),
  );
console.log(JSON.stringify(names));
await page.screenshot({ path: "/tmp/probe.png" });

Lies dann den Screenshot. Der Auszug sagt dir, dass ein Name existiert; nur das Bild sagt dir, was das Steuerelement ist. Vier Arten, wie das beißt:

  • Ein Name, der nicht das ist, was du vermuten würdest. Der zugängliche Name eines Umschalters war der Name des derzeit ausgewählten Elements, nicht "Projekt auswählen".
  • Ein Name, der nicht das ist, wonach er klingt. Ein Dateien-Button in einer Seitenleiste war ein Abschnitts-Umschalter, sodass das Anklicken den Abschnitt einklappte, anstatt irgendwohin zu navigieren. Das wurde in einen Take ausgeliefert.
  • Ein Name, der Teil eines anderen Namens ist. getByLabel("Erste Nachricht") traf auch auf eine nahegelegene Option zu, deren Label "erste Nachricht" enthielt, sodass die Eingabe nie das Feld erreichte und nichts fehlschlug. Verwende exact: true oder stimme zusätzlich auf die Rolle ab.
  • Etwas, das wie Text aussieht, aber keiner ist. Eine Auswahl-Überschrift, die von einem Screenshot abgelesen wurde, war ein Platzhalter eines Eingabefelds, sodass getByText sie nie finden konnte. Bestätige, dass ein Locator aufgelöst wird, bevor du dagegen ein Skript schreibst.

Wenn mehrere Elemente einen Namen teilen – ein Element erscheint in der Seitenleiste, der Seitenkopf und einem Breadcrumb – begrenze mit .first().

Treibe es so an, wie es eine Person tun würde

Finde Steuerelemente anhand der sichtbaren Rolle oder des sichtbaren Textes (getByRole, getByText, getByLabel, getByPlaceholder). Niemals CSS-Selektoren, niemals test-only-Attribute und niemals einen Hook in die App einbauen, damit eine Aufnahme etwas finden kann. Demo-Skripte sind Einweg- und PR-bezogen; halte sie außerhalb des Repositorys.

Ändere niemals die App, das Skill oder den Produktionscode für eine Demo. Wenn die Demo eine andere App benötigt, ist die Demo falsch.

Warte niemals auf die Uhr

waitForTimeout(9000), um "den Editor laden zu lassen", ist der mit Abstand häufigste Grund für ansehbare, aber langweilige Demos. Es zahlt immer den schlimmsten Fall, und jede dieser Sekunden ist in der Datei. Warte auf das Ding, auf das du tatsächlich wartest – das erste Steuerelement, mit dem du interagieren wirst – damit die Demo in dem Moment weitergeht, in dem die App bereit ist, und laut fehlschlägt, den Locator nennt, anstatt eine halb aufgebaute Seite zu bedienen.

Feste Pausen sind nur für das Tempo da: ein Schlag nach einer Aktion, damit ein Zuschauer aufnehmen kann, was sich geändert hat. Sekunden, nicht zehn Sekunden, und niemals als Ersatz für ein Warten.

Eine geschriebene Datei ist kein Beweis

Rekorder spülen eine partielle Datei, wenn das Skript einen Fehler wirft, und einige Aufnahmewerkzeuge schreiben beim Beenden, was immer passiert ist. Die Existenz der Datei allein sagt also nichts aus. Bevor du einem Take glaubst:

  • Überprüfe den Exit-Status und stderr und lies den Fehler, falls es einen gibt – er nennt meist den Locator, der nichts gefunden hat.
  • Überprüfe auf eine veraltete Aufnahme, die bereits den Ausgabepfad hält. Eine Aufnahme, die von einem früheren Versuch noch läuft, besitzt immer noch den Dateinamen und wird stillschweigend eine Aufnahme der falschen Sache produzieren.
  • Überprüfe die Frames. Extrahiere ein Kontaktblatt, den letzten Frame und jeden Übergang, bei dem du unsicher bist, und sieh sie dir an.

Überprüfe die Demo, nicht das Skript

Ein sauberer Exit sagt, dass das Skript gelaufen ist, nicht dass die Funktion funktioniert hat. Bestätige beides:

  • Visuell – die Änderung ist in den Frames auf dem Bildschirm, in dem Zustand, den die Anfrage verlangt hat.
  • Funktional – der persistierte Zustand hat sich tatsächlich geändert, aus der Datenbank oder der API gelesen, nicht aus der UI geschlossen.

Wenn die Behauptung das Layout betrifft – zwei Bereiche nebeneinander, ein Panel an eine Kante angedockt –, behaupte es aus den Bounding-Boxen. Dass Elemente existieren, sagt nichts darüber, wo sie sind.

Halte den Endzustand etwa drei Sekunden lang, damit der Zuschauer darauf landet, dann überprüfe den Codec, die Abmessungen und die Dauer der Ausgabedatei mit ffprobe, bevor du sie übergibst.

Bewahre die Beweise auf

Bewahre Fehlerprotokolle, Teil-Takes und Screenshots auf, bis ein Take erfolgreich war. Lösche flüchtigen Zustand erst, nachdem du etwas hast, das du ausliefern würdest. Ein verworfener Zwischenschritt ist oft die einzige Aufzeichnung warum der Take schiefging.

Störe nicht den Rechner, auf dem du aufnimmst

Eine lokale Aufnahme läuft auf dem tatsächlichen Computer einer Person, während sie ihn benutzt.

  • Gib der App ein eigenes einmaliges Profil und berühre niemals das echte Profil des Bedieners.
  • Bereite alles vor, was die Demo benötigt, bevor der erste Start erfolgt, sonst erscheinen Einrichtungsbildschirme vor ihnen.
  • Kontrolliere jeden Prozess, den du startest, und stoppe ihn, wenn du fertig bist – insbesondere Aufnahmen, die weiterlaufen, nachdem das Skript zurückgekehrt ist.
  • Starte langlaufende Prozesse als Hintergrundaufgaben, für die du ein Handle hältst, nicht mit einem nachgestellten & innerhalb eines Vordergrund-Wrappers: Wenn der Wrapper beendet wird, nimmt er den Server mit.
  • Stoppe einen Prozess so, wie er erwartet, gestoppt zu werden. Ein Development-Server, der mit SIGKILL getötet wurde, übersprang seinen Cleanup-Trap und hinterließ eine neu geschriebene Env-Datei und eine veraltete Port-Datei. Signaliere den Prozess, den du gestartet hast, und lass ihn aufräumen. Niemals mit Muster töten (pkill -f next): Auf einem gemeinsamen Rechner löscht das auch die Server anderer Leute.
  • Überprüfe, mit welchem Backend die App unter Demo spricht. Ein Entwicklungsstarter standardmäßig auf eine Produktions-API, wenn nicht anders angegeben, sodass die Klicks einer Demo echte Daten geschrieben hätten. Richte es vor dem ersten Take auf ein lokales oder Entwicklungs-Backend aus.
  • Prüfe alles Externe, auf das die Demo angewiesen ist – eine CLI, die angemeldet sein muss, einen Dienst, der verfügbar sein muss –, bevor du ein Display nimmst oder die Aufnahme startest, damit eine fehlende Abhängigkeit in einer Sekunde fehlschlägt, nicht mitten im Take. Führe niemals eine Aktion mit Seiteneffekten aus, z. B. das Senden einer Nachricht, nur um zu beweisen, dass ein Werkzeug gestartet wurde.
  • Wenn ein Take ihren Bildschirm, ihren Fenstermanager oder ihre Eingabe benötigt, sage das und frage, anstatt es einfach zu nehmen.

Die Datei auf einen PR bekommen

gh lädt das Video selbst hoch, seit v2.99.0:

gh pr comment <number> --body-file ./note.md --attach ./demo.mp4

--attach funktioniert auch bei gh pr create, gh pr edit und den entsprechenden gh issue-Befehlen. Es ist wiederholbar, bis zu 50 Dateien pro Befehl, und lädt auf das user-attachments-CDN hoch, sodass GitHub das Video inline rendert.

Vier Dinge, die wissenswert sind:

  • Alt-Text ist nur für Bilder. './shot.png#The error state' setzt Alt-Text auf einem Bild; die gleiche Syntax wird bei einem Video mit cannot set alt text on video abgelehnt. Hänge Videos mit einem bloßen Pfad an.
  • Ein Body, der bereits den lokalen Pfad referenziert, wird umgeschrieben. Schreibe ![alt](./demo.mp4) an die Stelle, an der es sein soll, und gh tauscht die hochgeladene URL ein; andernfalls wird der Anhang an das Ende angehängt.
  • gh pr edit --attach ohne Body-Flag behält den vorhandenen Body und hängt an ihn an, sodass eine Demo nachträglich zur PR-Beschreibung hinzugefügt werden kann.
  • Überprüfe die Version, bevor du dich darauf verlässt. Bei gh älter als 2.99.0 gibt es kein --attach und das CDN ist auf keinem anderen Weg durch die API erreichbar – falle also darauf zurück, der Person den Dateipfad zu geben, damit sie ihn selbst in den PR ziehen kann.

Verwandte Skills