paas — Ops-Dienst der vibe-apps-Plattform. Namen sind App-Namen (probe-elixir, notetaker), nie UUIDs. Beide Klassen, dieselben Verben: Single-App (Coolify-Application) und Compose-App (Coolify-Service) — der Typ steht in der Antwort, nie im Befehl. Trifft der App-Tag beide Typen, bricht der Dienst ab (409) statt still den ersten zu nehmen. Lesen (GET, Lese-Token — kann nicht schreiben): show alles zu einer App: UUID, Domain, Ressourcen (Datenbank, Backups), Env-Keys, Status, Repo; Compose-App: dazu die Container und der Netz-Anschluss — kein Deployment-Verlauf (Services stehen nicht in /deployments) status [] läuft es, ist es healthy — ohne Name alle Apps beider Klassen. Compose-App: Aggregat plus eine Zeile pro Container; One-Shots (restart: no) zählen nicht ins Aggregat und ihr Exit-Code ist per API unbekannt; das Aggregat läuft dem Container-Zustand minutenlang nach (compose-apps.md) logs [container] [-n N] die letzten N Zeilen (Default 100). Compose-App: ein Container oder ohne Angabe alle nacheinander; beendete Container (One-Shots) liefert Coolify nicht — nur über den SSH-Seam des Dienstes (Env APP_VM_SSH_HOST), sonst nennt die Antwort die Lücke und das Handkommando envs [--show-values] Env-Keys mit Zustand gesetzt/leer/doppelt; Werte nur mit --show-values (warnt) probe gescripteter SSO-Login mit dem Testnutzer: anonym muss die App 302 zur Keycloak-Auth-URL umleiten, eingeloggt 200 mit Inhalt liefern — beantwortet „kommt ein Firmennutzer an?“, nicht nur „Container läuft“. Rot ⇒ zuerst die SSO-Kette verdächtigen (sso.md). Compose-App: Domain des Web-Containers. Kommando im App-Container (POST, SSH-Seam, App-Recht): exec [--timeout=N] -- [argumente…] Nicht-interaktiv, kein TTY. Default 60 s, erlaubt 1–600; stdout/stderr zusammen maximal 64 KiB, gekappte Ausgabe wird markiert, Exit-Code bleibt in der Antwort. Timeout: 504 mit Handkommando; Prozess kann weiterlaufen. Compose: Containername aus status. Single-App: Coolify-Containername (UUID, UUID-Zeitstempel oder UUID-pr-N). Nach -- bleiben alle Argumente unverändert. Ohne APP_VM_SSH_HOST: 503. Audit enthält keine Argumente/Ausgabe. Ändern (POST, Schreib-Token): env-set KEY=wert [KEY=wert…] Envs anlegen oder ändern — wirken erst nach restart/deploy (mehrere Envs, ein restart); Werte werden nie zurückgegeben env-del KEY Env löschen — wirkt erst nach restart/deploy restart neuer Container, Envs werden neu eingelesen. Bei Image-Apps (alle Apps der Plattform) zieht Coolify dabei das Image genauso neu wie deploy — restart_only gilt nur für Git-Buildpacks; ein neueres :latest kommt mit. Compose-App: alle Container werden neu erstellt (compose up mit force-recreate), die One-Shots laufen erneut; kein Deployment-Eintrag. deploy [--timeout=N] zieht das Image aus der Registry neu — derselbe Webhook wie am Ende der grünen Pipeline. Kein Weg um das Gate: eine rote Pipeline hat kein Image gepusht, deploy holt nur, was dort liegt. Single-App: eingereiht, Antwort sofort mit Deployment-UUID. Compose-App: blockiert und pollt GET /services/ alle 10 s bis zum stabilen Ergebnis (Default 300 s, mindestens 30): alle zählenden Container laufen, One-Shots beendet, drei gleiche Lesungen (das Aggregat zeigt transient exited). Urteil stabil / fehlgeschlagen (One-Shot mit Exit ≠ 0, nur mit SSH-Seam feststellbar) / timeout — das Deploy läuft dann weiter, status zeigt es. neu [--db] [--port=N] Coolify-Hälfte einer neuen Single-App: Application als Docker-Image (Domain .apps…, Healthcheck, Tag app:, Limits 2 GB / 1 vCPU — Plattform-Default ohne Schalter (#42), Env PORT — Default 3000), mit --db Postgres -db samt Backup-Plan und DATABASE_URL. Wiederaufnahme: was schon da ist, wird gemeldet, nicht doppelt angelegt. Den ganzen Ablauf inklusive GitLab-Repo, CI-Variablen und erstem Push fährt lokal bin/neu — dieses Verb ist dessen Coolify-Schritt. Compose-Apps legt kein Verb an: Skill compose-app-anlegen (Ops-Repo), Regeln in compose-apps.md. Antwort als JSON: Accept: application/json (Client: --json). GET auf ein änderndes Verb ⇒ 405 mit Allow: POST.