Ich steckte bis zum Hals in einer Avatar-Pipeline und brauchte zwei unglamouröse Dinge gleichzeitig: einen Lipsync-Durchlauf, und eine Handvoll ffmpeg-Operationen drumherum, die Quelle schneiden, den Ton muxen, die Ausgabe transkodieren, ein Thumbnail-Blatt rausschneiden. Jede “Lösung”, die ich fand, war irgendein SaaS-Wrapper um ein Modell, das ich nicht inspizieren konnte, pro Sekunde Ausgabe abgerechnet, hinter einem API-Key weggesperrt, mit einem Wasserzeichen in der Ecke eingebacken, weil es ja nicht sein darf, dass ich 40 Dollar im Monat zahle und trotzdem meinen eigenen Render besitze. Einer davon wollte mein Gesichtsvideo UND meinen Ton auf seine Server hochgeladen haben, bevor er mir überhaupt einen Preis nannte. Ein anderer hatte eine “kommerzielle Lizenz”-Stufe, die mehr kostete als meine Grafikkarte. Ich saß da und dachte: ich habe eine 3060, die in einem Gehäuse liegt und nach 18 Uhr nichts tut, ffmpeg gibt es, seit die Welt sich dreht, und Wav2Lip ist seit 2020 Open Source. Warum zum Teufel miete ich das von einem Fremden.
Also habe ich es gelassen. flickies ist die Video-Hälfte des selbstgehosteten Werkzeugkastens, den ich seit einer Weile baue, docker run, du richtest es auf ein Gesicht und eine Tonspur, du bekommst ein mp4 zurück. Kein Konto, kein Sekundenzähler, kein Wasserzeichen, kein Hochladen meines Krams auf die Inferenzfarm von irgendwem. Es ist der Bruder von audiolla (Audio) und talkies (Sprache), dasselbe Modell asynchroner Jobs, dieselbe Bind-Mount-/data-Geschichte, dieselbe nicht-kommerzielle Opt-in-Schranke, dieselbe Haltung von “ein Port, null Cloud”. Es klinkt sich direkt in aigate als Video-Engine ein, hinter derselben nginx-Eingangstür wie alles andere, was bei mir läuft.
Dein Eigenes Gesicht Zurückmieten
Lipsync als Cloud-Dienst ist eine ganz eigene Sorte Abzocke, und ich habe eine Liste:
- Du lädst ein menschliches Gesicht auf die GPU eines Fremden. Kein Katzenbild. Ein Gesicht, das genau den Scheiß sagt, den du dem Ton vorgegeben hast. Diese Daten verdunsten nicht, wenn der Render fertig ist, sie liegen auf der Platte von jemand anderem, mit der Aufbewahrungsrichtlinie von jemand anderem.
- Abrechnung pro Sekunde Ausgabe macht aus dem Experimentieren eine Buchhaltungsübung. Du willst zehn Takes durchprobieren, bis der Sync sitzt? Glückwunsch, du hast gerade zehnmal bezahlt.
- Wasserzeichen und Tarifmauern, die “kostenlose” Stufe klatscht ein Logo auf deine Ausgabe, und die bezahlte Stufe, die es entfernt, kostet mehr als die Hardware, auf der du das an einem Wochenende lokal laufen lassen würdest.
- Niemand erzählt dir die Lizenzgeschichte. Eine erschreckende Anzahl dieser SaaS-Wrapper sitzt auf Wav2Lip, das auf LRS2 trainiert ist, einem Datensatz mit ausdrücklicher Nicht-Kommerz-Klausel. Das SaaS nimmt dir Geld ab, um ein nicht-kommerzielles Modell laufen zu lassen, und erwähnt diesen Teil einfach… nicht. Das ist nicht mein Problem, wenn du selbst hostest, aber ich lasse dich wenigstens aktiv einen Schalter umlegen, um es anzuerkennen, statt es in AGB zu verstecken, die keiner liest.
- Null Einsicht. Du bekommst einen Blackbox-REST-Endpoint und ein “vertrau uns”, keine Ahnung, welche Modellvariante lief, mit welchen Einstellungen, ob dein Gesichtsrestaurierungs-Durchlauf drangehängt ist oder nicht.
Und auf der ffmpeg-Seite, schneiden, transkodieren, Ton auf ein Video klatschen, ein Thumbnail-Raster ziehen, jede “Videoverarbeitungs-API”, die ich dafür fand, war irgendwie AUCH ein Bezahlprodukt, für Operationen, die aus einem ffmpeg-Aufruf mit den richtigen Flags bestehen. Reine Dateiverarbeitung über die Leitung hatte ich mit mediaproc schon gelöst; flickies macht dasselbe “ruf ein echtes Werkzeug auf, hör auf, es neu zu erfinden”, nur speziell auf Video zugeschnitten und zusätzlich für die ML-Hälfte verdrahtet.
Erst die Spec, Dann der Container
flickies ist ein FastAPI-Dienst, der ein einziges Leitungsformat für zwei sehr verschiedene Arten von Arbeit spricht: reine ffmpeg-Operationen auf der CPU, und Modellinferenz auf der GPU für Lipsync und Gesichtsrestaurierung. Jeder Endpoint, der Video erzeugt, nimmt dieselbe Anfrageform: genau eine Eingabe (file_path lokal bereitgelegt, oder file_url, die der Server für dich holt) und genau eine Ausgabe (output_path unter FILES_DIR geschrieben, oder output_url, an die der Server das Ergebnis PUTtet, vorsignierte S3-URL, was auch immer). Beliebig mischbar. Leg eine Datei lokal hin, bekomm eine vorsignierte URL zurück. Hol von einer URL, schreib auf die lokale Platte. Es ist ihm egal.
Die ML-Seite läuft über eine Registry, die einen einzigen GPU-Pool mit Hot-Swap-Verdrängung verwaltet: du forderst wav2lip an, es lädt. Du forderst als Nächstes gfpgan an, die Registry verdrängt zuerst wav2lip (del auf die Referenzen, gc.collect(), dann torch.cuda.empty_cache(), genau in dieser Reihenfolge, denn PyTorch-Modellgraphen halten Referenzzyklen, und den gc.collect()-Schritt zu überspringen heißt, dass das “Entladen” eines Modells den VRAM gar nicht freigibt, ein Bug, den ich in v0.1.0/v0.2.0 ausgeliefert und in v0.3.1 wirklich behoben habe). Ein Hintergrund-Kehrer entlädt außerdem, was gerade resident ist, sobald es länger untätig war als FLICKIES_IDLE_UNLOAD_SECS (Standard 600s). Ein Modell lebt zu einem Zeitpunkt im VRAM; das ist das ganze Design.
Alles, was danach kommt, die Routen, die Anfrage- und Antwortformen, die Fehlercodes, stammt aus einer einzigen Datei: openapi.yaml. Das ist keine nachträglich geschriebene Dokumentation, das ist die tatsächliche Generator-Eingabe für drei getrennte Dinge: die Pydantic-Validierungsmodelle des Servers, den Go-Client und den Python-Client. Ändere die Spec, lass make generate laufen, alle drei werden zusammen neu erzeugt. make generate-check ist eine CI-Schranke, die den Build scheitern lässt, wenn eines davon von der Spec abdriftet. Warum das zählt, kommt weiter unten, denn das ist der Teil dieses Projekts, mit dem ich am meisten angebe.
Schnellstart
docker run -d --name flickies
-v $HOME/flickies-data:/data
-p 8000:8000
psyb0t/flickies:latest
curl -s -X POST https://ciprian.51k.eu00/v1/video/info
-H "Content-Type: application/json"
-d '{"file_path": "uploads/clip.mp4"}' | jqZwei Images: psyb0t/flickies:latest (CPU, Basis python:3.12-slim) und psyb0t/flickies:latest-cuda (Basis nvidia/cuda 12.4 runtime). Das CPU-Image fährt jede ffmpeg-Operation plus Wav2Lip auf der CPU, langsam, aber echt; das CUDA-Image fährt alles in einem Tempo, das du tatsächlich aushalten würdest. Getestetes Ziel ist eine RTX 3060 mit 12GB.
Vier ML-Engines: Lipsync und Gesichtsrestaurierung
engines.json definiert genau vier ML-Engines, jede mit einem Slug, einem CUDA-Pflicht-Flag, einer VRAM-Untergrenze und, wo es zählt, einer Lizenzschranke:
wav2lip / wav2lip-gan
Rudrabha/Wav2Lip, ins Repo geholt, native Auflösung 96×96. Zwei Varianten, die sich eine Engine-Klasse teilen, umgeschaltet über ein variant-Feld: base (maximale Sync-Genauigkeit, weicherer Mund) und gan (GAN-Verfeinerer, schärferer Mund, ganz leicht schlechterer Sync). Beide wählen ihr Gerät selbst, FLICKIES_DEVICE=auto prüft torch.cuda.is_available() und fällt sauber auf CPU zurück. Im Benchmark des ersten Release sind das ~44 Sekunden für einen 3-Sekunden-Clip auf der CPU, ~22 Sekunden auf der GPU. Diese CPU-Zahl ist kein Witz, sie ist für kurze Clips wirklich brauchbar, was ich von den meisten Open-Source-Lipsync-Repos mit “GPU erforderlich” nicht behaupten kann, die auf einer Maschine ohne Karte einfach abstürzen, statt sich elegant zu verschlechtern.
latentsync-1.5
ByteDances LatentSync 1.5, Apache-2.0, absichtlich auf den 1.5-Checkpoint festgenagelt, weil 1.6 18GB VRAM will und meine Hardware-Decke bei 12 liegt. Rückgrat im SD-1.5-Latentraum, Whisper-tiny-Audio-Embeddings mit Cross-Attention in ein UNet3D via AnimateDiff, schwerere Maschinerie als Wav2Lip, und man merkt es: ~170 Sekunden für einen 6-Sekunden-Clip auf der 3060, mit Spitze um 9.6GB VRAM. Das ist die einzige Engine im ganzen Satz, die CUDA zwingend voraussetzt, der Code prüft beim Laden torch.cuda.is_available() und wirft einen 400, wenn es nicht da ist, ohne jeden Versuch eines CPU-Rückfalls. Sie ist außerdem die Standard-Engine, solange die Nicht-Kommerz-Schranke nicht aktiv zugestimmt wurde, denn anders als Wav2Lip schleppt sie kein LRS2-Gepäck mit sich.
gfpgan
TencentARCs GFPGAN v1.4, Apache-2.0. Das hängt sich hinter Wav2Lip, um den weichen, niedrig aufgelösten Mundausschnitt zu reparieren, den die native 96×96-Inferenz hinterlässt, Wav2Lip trifft den Sync, GFPGAN räumt das optische Chaos drumherum auf. Es läuft auch allein über POST /v1/video/restore, wenn du nur einen Gesichtsrestaurierungs-Durchlauf über vorhandenes Material willst. Dieselbe automatische Geräteauswahl wie Wav2Lip, Rückfall auf CPU. Bild für Bild: lesen über cv2, den Restaurator pro Bild laufen lassen, in ein stummes mp4 schreiben, dann den Originalton wieder über die restaurierten Bilder muxen.
Die Gewichte für alle vier liegen im Standard-HuggingFace-Cache-Layout unter /data/hf/hub/models--<org>--<name>/, inhaltsadressierte Blobs, Snapshot-Symlinks, wiederverwendbar von allem anderen HF-Bewussten, das denselben Bind-Mount teilt. Standardmäßig faul: jede Engine holt ihr Repo bei der ersten Anfrage. FLICKIES_PREFETCH_ALL=1 oder ein eingegrenztes FLICKIES_ENABLED_ENGINES=wav2lip,gfpgan zieht die Gewichte beim Start, noch bevor uvicorn überhaupt hochfährt, damit deine erste echte Anfrage keine minutenlange Kaltdownload-Strafe frisst.
Die Lizenzschranke ist nicht dekorativ
Wav2Lips Gewichte sind auf LRS2 trainiert, einem nicht-kommerziellen Datensatz. flickies vergräbt das nicht in einem README, das keiner liest, der Servercode weigert sich physisch, irgendeine der beiden wav2lip-Varianten zu laden, solange FLICKIES_ENABLE_NONCOMMERCIAL=1 nicht in der Serverumgebung gesetzt ist. Versuch, die Engine ohne das zu bekommen, und require_noncommercial_optin() wirft ein NonCommercialOptInRequired, das die API als ordentlichen Fehler an die Oberfläche bringt statt als stillen 500. LatentSync 1.5 und GFPGAN sind beide Apache-2.0, keine Schranke, freies Laden. Derselbe Mechanismus, den audiolla für seine eigenen Nicht-Kommerz-Schranken bei MusicGen und matchering benutzt, ich habe das Muster bei mir selbst geklaut, was ich darf.
Sieben ffmpeg-Operationen, Weil Nicht Alles Eine GPU Braucht
Die Hälfte dessen, was Leute von einer “Video-API” tatsächlich brauchen, ist überhaupt kein ML, es ist ffmpeg mit vernünftigen Defaults und Fehlerbehandlung. flickies bietet sieben reine ffmpeg-Operationen, kein Modell geladen, reine CPU, in beiden Images verfügbar:
- trim, schneidet auf
[start_sec, end_sec]. Der Standardmodus ist Stream-Copy mit-c copy(schnell, springt aber auf den nächstgelegenen Keyframe, kann bis zu einem GOP am Anfang wegfressen). Setzprecise: trueund es kodiert überlibx264 -crf 18 -preset veryfastplus AAC 192k neu, für bildgenaue Grenzen. - concat, fügt 2 oder mehr Videos der Reihe nach über den concat-Demuxer zusammen. Derselbe Kompromiss zwischen Stream-Copy und präzise wie bei trim;
precise: truekodiert durch den Demuxer mit einheitlichen Codec-Parametern neu, damit Eingaben mit ungleichen Encodern wirklich zusammengehen statt zu zerfallen. - transcode, universelle Neukodierung quer über mp4/webm/mov/mkv, mit Codec-, crf-, Preset- und fps-Overrides. Behandelt auch gif-Ausgabe als speziellen Zweipass-Pfad:
palettegen, dannpaletteusedurch ein filter_complex, weil eine naive ffmpeg-nach-gif-Konvertierung wie Müll aussieht und das jeder weiß. - scale, skaliert auf Breite×Höhe, mit optionalem seitenverhältniswahrendem Pad.
- mux_audio, ersetzt eine Tonspur in einem Video oder mischt sie hinein.
- extract_audio, zieht die Tonspur als wav/mp3/m4a/ogg/flac heraus.
- thumbnail_grid, Sprite-Sheet-PNG über die Filter
thumbnailundtile, Zeilen, Spalten und Zellgröße alle konfigurierbar.
Es gibt eine achte Video-Fähigkeit, die nicht in dieser “Operationen”-Liste steht, weil sie kein Video erzeugt, /v1/video/info ruft ffprobe auf und gibt dir Dauer, Codec, fps, Abmessungen, Bitrate zurück. Jede einzelne davon läuft durch einen einzigen Engpass in ffmpeg.py, der den Prozess über asyncio.create_subprocess_exec startet, stderr einfängt und bei einem Exit-Code ungleich null einen strukturierten FFMPEG_FAILED-Fehler wirft, statt einen rohen Traceback durchsickern zu lassen.
Asynchrone Jobs und Webhooks, Für Wenn Du Nicht Daneben Sitzen und Warten Willst
LatentSync mit über 170 Sekunden pro Clip ist nichts, wofür du eine HTTP-Verbindung offen halten willst. Jeder Endpoint, der Video erzeugt, nimmt async_job: true an (oder du lässt einfach beide Ausgabefelder weg und es ist impliziert): der Server reserviert vorab eine Job-ID, plant die Arbeit als asyncio-Hintergrundtask und gibt sofort 202 {job_id, status: "accepted"} zurück. Du fragst GET /v1/jobs/{job_id} ab für pending → running → complete/failed/cancelled. Willst du nicht pollen, übergib eine webhook_url und der Server liefert den Endzustand des Jobs selbst aus.
Die Webhook-Zustellung ist kein hingeworfenes POST mit Schulterzucken. Sie ist HMAC-SHA256-signiert über timestamp + "." + body, geschickt als Header X-Webhook-Timestamp und X-Webhook-Signature: t={ts},v1={hex}, mit einem echten Wiederholungsplan mit exponentiellem Backoff bei allem, was kein 2xx ist: 30s, 1m, 5m, 30m, 2h, 12h, dann schreibt er einen Dead-Letter-Eintrag und gibt auf. Von deinem Empfänger wird erwartet, dass er über (timestamp, signature) dedupliziert, der Idempotenz wegen. Das hat dieselbe Form wie der Webhook-Vertrag eines Zahlungsdienstleisters, denn das ist der einzige Stand der Technik, der es wert ist, für “jemandem zuverlässig sagen, dass ein langer Job fertig ist” kopiert zu werden.
Elf Werkzeuge Auf der MCP-Leitung
Gemountet auf /v1/mcp als JSON-RPC über streamable HTTP, bietet flickies elf MCP-Tools, die die REST-Oberfläche fast 1:1 spiegeln: list_engines, info, lipsync, restore, transcode, trim, concat, scale, mux_audio, extract_audio, thumbnail_grid. Richte ein Modell mit Function Calling darauf, LibreChat, Cursor, Claude mit dem MCP-Connector, welches Agenten-Framework du auch fährst, und es kann die ganze Pipeline selbst steuern: ein Gesichtsvideo bereitlegen, einen Audioclip bereitlegen, lipsync mit restore_face: true aufrufen, um GFPGAN nach dem Sync-Durchlauf automatisch anzuhängen (was, erwähnenswert, mitten im Tool-Aufruf eine Hot-Swap-Verdrängung des Lipsync-Modells auslöst, das ist Absicht, es gibt den VRAM frei, den der Restaurierungs-Durchlauf braucht), und dir dann einen Pfad oder eine Größe zurückgeben.
Das ist auch die Schicht, auf die aigate weiterleitet, wenn du FLICKIES=1 oder FLICKIES_CUDA=1 umlegst, eine einzige nginx-Eingangstür vor jedem meiner selbstgehosteten KI-Dienste, diesen eingeschlossen.
Spec Zuerst: Go- und Python-Clients Aus Derselben Verdammten Datei Generiert
Das ist für mich der Teil, der flickies wirklich von “noch ein ML-Wrapper-API” abhebt. openapi.yaml ist keine Deko, die nach dem Code geschrieben wurde, um professionell auszusehen, es ist die einzige Quelle der Wahrheit, AUS der drei getrennte Artefakte generiert werden, nicht passend dazu geschrieben:
make generate # regenerate all three: server models + Go client + Python client
make generate-models # just server-side Pydantic (src/flickies/schema/_generated.py)
make generate-client-go # just the Go client (pkg/clients/go/client.gen.go)
make generate-client-python # just the Python client (pkg/clients/python/flickies-client/)
make generate-check # CI gate — fails the build if generated files drift from openapi.yamlGenerierte Dateien niemals von Hand bearbeiten. Bearbeite die Spec, lass make generate laufen, committe alles zusammen. Der Go-Client kommt von oapi-codegen, der Python-Client von openapi-python-client, beides echte, typisierte, importierbare Pakete, keine nachträglich in eine Funktion gewickelten curl-Aufrufe:
go get github.com/psyb0t/docker-flickies/pkg/clients/go@latestimport flickies "github.com/psyb0t/docker-flickies/pkg/clients/go"
c, _ := flickies.NewClient("https://ciprian.51k.eu00")
resp, err := c.PostVideoLipsync(ctx, flickies.VideoLipsyncRequest{...})pip install "git+https://github.com/psyb0t/docker-flickies.git#subdirectory=pkg/clients/python/flickies-client"from flickies_client import Client
from flickies_client.api.lipsync import post_video_lipsync
from flickies_client.models import VideoLipsyncRequest
client = Client(base_url="https://ciprian.51k.eu00")
result = post_video_lipsync.sync(client=client, body=VideoLipsyncRequest(...))Es ist nicht perfekt, den Structs VideoTrimRequest und VideoConcatRequest des Go-Clients fehlen derzeit start_sec/end_sec/precise, wegen einer bekannten Einschränkung von oapi-codegen bei über allOf zusammengesetzten Schemata (der inline-properties-Block am zusammengesetzten Typ fällt weg). Go-Aufrufer serialisieren genau diese Bodies derweil über map[string]any. Mir ist eine dokumentierte echte Generator-Einschränkung lieber, als so zu tun, als wäre die Pipeline makellos, der Punkt ist nicht, dass Codegenerierung Magie wäre, sondern dass die Spec und jeder Client, der sie spricht, mechanisch gar nicht auseinanderlaufen können, weil sie alle aus demselben Build-Schritt stammen.
Logging, Auth, Rate Limits, Der Langweilige Kram, Der Um 3 Uhr Nachts Wirklich Zählt
Strukturiertes JSON-Logging geht auf stderr UND in eine rotierende Datei (FLICKIES_LOG_FILE, Standard 50MB × 5 Sicherungen), mit einem eigenen Formatter, der alles rekursiv schwärzt, was auf password|token|secret|api_key|authorization|cookie|hf_*|sk-ant-* passt, in Schlüsseln wie in Werten, zum Formatierungszeitpunkt, bevor die Zeile überhaupt geschrieben wird. Jeder Log-Eintrag trägt eine trace_id und eine request_id, durch eine ContextVar gefädelt, aus dem eingehenden X-Request-Id-Header gespeist, sofern der formgültig ist (UUID v4 oder ULID, höchstens 64 Zeichen, keine Zeilenumbrüche, Mülleingaben bekommen einfach eine frisch geprägte UUID, statt zurückgespiegelt zu werden, was einen Log-Injection-Vektor schließt). Setz FLICKIES_LOG_LEVEL=DEBUG und du bekommst Tracing in Rekonstruktionsqualität: jedes ffmpeg- und ffprobe-Kommando, jede trim- oder concat-Entscheidung zwischen Stream-Copy und präziser Neukodierung, die Inferenz-Laufzeit jeder Engine, die geholten und hochgeladenen Bytes pro URL, die Lebenszyklus-Übergänge der Jobs. Geloggten URLs wird zuerst der Query-String abgeschnitten, eine vorsignierte output_url lässt ihre Signatur also nicht in deine Logdateien durchsickern.
Die Auth ist ein statischer Bearer Token über FLICKIES_AUTH_TOKEN, mit hmac.compare_digest geprüft, damit sie nicht über Zeitmessung angreifbar ist, /healthz ausgenommen, damit die Probes deines Orchestrators weiter funktionieren. Setz die Variable nicht und die Auth ist schlicht aus, deine Entscheidung, deine Netzgrenze. Obendrauf: ein Token-Bucket-Rate-Limiter pro IP (Standard 60 Anfragen pro Minute, einstellbar), und eine Idempotency-Key-basierte Dedupe-Schicht, die (Status, Body) pro (Key, Methode, Pfad) cacht, damit ein wiederholtes POST einen teuren Render nicht doppelt fährt. Alle drei sind ASGI-Middleware aus reiner Standardbibliothek, keine zusätzliche Abhängigkeit nur fürs Rate-Limiting.
Wo Es Wohnt
flickies mountet sich innerhalb von aigate auf /flickies/ und /flickies-cuda/, hinter demselben nginx, der vor jedem anderen selbstgehosteten KI-Dienst steht, den ich betreibe, ein make run-bg, beide Varianten mit FLICKIES=1 und FLICKIES_CUDA=1 umgelegt. Es ist das video-förmige Teil desselben Puzzles, das audiolla und talkies für Audio und Sprache ausfüllen, derselbe Leitungsvertrag, dieselbe Ergonomie für den Betreiber, einen vierten oder fünften Dienst später in diesen Stack zu hängen heißt also nicht, alles neu zu lernen.
Was Du Tatsächlich Bekommst
flickies ist ein Video-Werkzeugkasten, der von Anfang an zufällig auch Lipsync enthält: vier echte Engines hinter einem einzigen Hot-Swap-GPU-Pool, sieben ffmpeg-Operationen, die nicht vorgeben, etwas Feineres als ffmpeg zu sein, asynchrone Jobs mit tatsächlich signierten Webhooks statt eines hingeworfenen POST, elf MCP-Tools für welchen Agenten auch immer du draufrichtest, und typisierte Clients in Go und Python, generiert aus genau der Spec, gegen die der Server validiert, nicht von Hand gepflegt, nicht abdriftend, nicht lügend darüber, was die API wirklich annimmt. Selbstgehostet, WTFPL, läuft auf einer GPU, die du schon besitzt.
Hol es dir bei github.com/psyb0t/docker-flickies oder zieh die Images direkt von Docker Hub. Mach damit, was du willst, aber hör auf, einem SaaS Geld zu geben, damit es ein Open-Source-Modell auf Hardware laufen lässt, die du dir mit drei Monaten ihrer Rechnung hättest komplett kaufen können.
Rein Damit In Deinen Agenten
Einem Agenten einen Video-Werkzeugkasten in die Hand zu drücken klappt besser, wenn er die Werkzeugliste schon kennt. Alles unter .agents/ ist in einem einzigen Marketplace katalogisiert, also sind es zwei Befehle:
claude plugin marketplace add psyb0t/agents
claude plugin install flickies@psyb0tCodex nutzt denselben Marketplace mit einem anderen Verb, codex plugin add flickies@psyb0t, weil es kein codex plugin install gibt. Er findet den Skill außerdem von allein in einem Checkout des Repos, da er .agents/skills/ nativ scannt, ganz ohne Installation. Es ist jetzt auch im offiziellen MCP Registry gelistet, ein Client, der seine Server von dort auflöst, kann es also finden, ohne dass man ihm eine URL gibt.