Contao-Summit 2026
Ergebnis 1 bis 13 von 13

Thema: Contao via SSH mit KI-Agenten steuern — contao-ai-cli + contao-ai-core-bundle

  1. #1
    Contao-Nutzer
    Registriert seit
    06.10.2011.
    Ort
    Wien
    Beiträge
    97

    HTML Contao via SSH mit KI-Agenten steuern — contao-ai-cli + contao-ai-core-bundle

    Ich habe zwei Pakete veröffentlicht, die Contao 5 für KI-Agenten (z.B. Claude Code) zugänglich machen:

    contao-ai-core-bundle — ein Contao-Bundle das CMS-Operationen als Symfony-Console-Commands bereitstellt: CRUD für Seiten, Artikel, Content-Elemente, News, Events, FAQs, Member, User, Files, Templates und Versionsverwaltung.
    https://github.com/webwerkwien/contao-ai-core-bundle

    contao-ai-cli — ein Python-CLI das sich per SSH mit der Contao-Installation verbindet und diese Commands für KI-Agenten zugänglich macht. Daneben auch direkt im Terminal nutzbar. Es kann alleine genutzt werden, hat aber mit dem obigen Paket weit mehr Funktionen.
    https://github.com/webwerkwien/contao-ai-cli

    Beide (KI-generierte) Pakete sind noch früh in der Entwicklung — produktiv eingesetzt habe ich sie bisher kaum, Feedback aus der Praxis ist daher sehr willkommen. Bisherige Tests haben sich vorwiegend auf Sicherheit und Code-Qualität beschränkt. Nicht in aktiven Websites nutzen. Die Anwendung ist nicht für Redakteure gedacht, für solche wird es ein Backend-Modul geben.

    Ich freue mich über Erfahrungsberichte und natürlich Issues auf GitHub.

  2. #2
    Contao-Nutzer
    Registriert seit
    06.10.2011.
    Ort
    Wien
    Beiträge
    97

    Standard Update: contao-ai-backend-bundle ist da + neue Macro-Engine im Core

    Kurzes Update zu der Pakete-Familie:

    contao-ai-backend-bundle ist jetzt veröffentlicht (v0.1.0, public): https://github.com/webwerkwien/contao-ai-backend-bundle

    Das ist das Backend-Modul, das ich oben angekündigt hatte — KI-Agent direkt im Contao-Backend, ohne SSH und ohne CLI. Editoren chatten im Browser mit Claude (oder GPT), der Agent kann lesen und schreiben mit denselben Permission-Checks wie ein normaler Backend-User. Jeder Backend-User trägt seinen eigenen API-Key (Anthropic oder OpenAI) ein, das Bundle bringt keinen mit.
    Code:
    composer require webwerkwien/contao-ai-backend-bundle
    contao-ai-core-bundle ist auf v0.2.0 gewachsen — neue Macro-Commands für Bulk-Operationen:

    contao:record:clone — News-Archive, Calendar, FAQ-Kategorie oder ganzen Seitenbaum mit allen Kindern in einer DB-Transaktion klonen
    contao:record:list — tabellenagnostisches Listing mit Filtern, Pagination, sauberen Default-Spalten
    contao-ai-cli ist auf v0.3.2 — neue bridge- und health-Befehle:

    contao-ai-cli bridge rewrite --table tl_news_archive --id 5 --recursive --instructions "..." ruft die Macros direkt im Backend-Bundle über HTTPS auf, der LLM-Loop läuft serverseitig. Praktisch für „alle 50 News auf Englisch" ohne Browser-Wechsel.
    contao-ai-cli health zeigt CLI-, Core- und Bridge-Stand auf einen Blick.
    Auth für die Bridge läuft über einen separaten Token, den jeder Backend-User in seinem Profil generieren kann (Hash-Storage, einmaliger Klartext-Anzeige). Editoren bleiben damit im Browser-Chat, Admins/Devs bleiben im Terminal.

    Status weiterhin Beta — in Produktivumgebungen weiter mit Vorsicht nutzen. Über Praxis-Feedback und GitHub-Issues freue ich mich.

  3. #3
    Contao-Urgestein Avatar von jan.theofel
    Registriert seit
    23.06.2009.
    Ort
    Berlin
    Beiträge
    1.857

    Standard

    Hi!

    Danke für die Extension!

    Ich versuche damit gerade für eine Migration zu nutzen. Abner ich scheitere bei den Bildern. Wenn ich ein Bild mittels contao:file:write einspiele und mittels contao:filesync n och synchronisiere. Woher bekomme ich dann die UUID um das Bild auch als Content-Element einfügen zu können?

    Danke
    Jan
    Jan Theofel
    Barcamp-Moderator für Corporate-Barcamps und öffentliche Barcamps

  4. #4
    Contao-Nutzer
    Registriert seit
    06.10.2011.
    Ort
    Wien
    Beiträge
    97

    Standard

    Servus! Das ist jetzt mit v0.2.1 (gerade veröffentlicht) gelöst — composer update webwerkwien/contao-ai-core-bundle (bzw. über die contao-ai-cli), dann:

    1. contao:file:write gibt jetzt die UUID zurück und synchronisiert die Datei direkt in die DBAFS — ein separates contao:filesync brauchst du dafür nicht mehr:

    Code:
    {"status":"ok","path":"files/dein/bild.jpg","bytes":12345,"version":false,"uuid":"c8045c91-8865-11f1-ba75-525400338fcc"}
    2. Diese UUID kannst du direkt in singleSRC setzen — content:create/content:update wandeln String-UUIDs jetzt automatisch in Contaos binäre Speicherform um (gilt für alle fileTree-Felder, also auch multiSRC):

    Code:
    contao:content:create --type=image --pid=<artikel-id> --set="singleSRC=c8045c91-8865-11f1-ba75-525400338fcc"
    Das Bild-Element referenziert die Datei danach korrekt — identisch zu einem im Backend angelegten Element.

    Nebenbei steckte in content:create noch ein Bug: invisible wurde als leerer String gesetzt, was unter striktem SQL-Modus (MariaDB) jedes Anlegen abbrechen ließ — ebenfalls in v0.2.1 behoben.

    Danke fürs Melden — hat direkt zwei Verbesserungen ausgelöst! Liebe Grüße!

  5. #5
    Contao-Urgestein Avatar von jan.theofel
    Registriert seit
    23.06.2009.
    Ort
    Berlin
    Beiträge
    1.857

    Standard

    Zitat Zitat von Creasign Beitrag anzeigen
    Servus! Das ist jetzt mit v0.2.1 (gerade veröffentlicht) gelöst

    Danke! Für diese Migration habe ich einen Workaround geschaffen und alle Bilder importiert und dan die UUID aus der Datenbank ausgelesen. Für die nächste Runde hilft das aber auf jeden Fall!
    Jan Theofel
    Barcamp-Moderator für Corporate-Barcamps und öffentliche Barcamps

  6. #6
    Contao-Urgestein Avatar von jan.theofel
    Registriert seit
    23.06.2009.
    Ort
    Berlin
    Beiträge
    1.857

    Standard

    Ich habe noch eine andere Stelle, die ich nicht in den Griff bekomme und auch keinen Workaroudn finde:
    Wie setze ich bei Content-Elementen neben der Überschrift set='headline=Foobar' auch die Überschriftenordnung h1-h6?
    Da das so ein kombiniertes Feld ist, finde ich da noch keinen Weg für.
    Jan Theofel
    Barcamp-Moderator für Corporate-Barcamps und öffentliche Barcamps

  7. #7
    Wandelndes Contao-Lexikon Avatar von zonky
    Registriert seit
    19.03.2010.
    Ort
    Berlin, Rdf
    Beiträge
    10.584
    User beschenken
    Wunschliste

    Standard

    guck dir mal einen Original-Datensatz an - serialisiertes Feld

  8. #8
    Contao-Urgestein Avatar von jan.theofel
    Registriert seit
    23.06.2009.
    Ort
    Berlin
    Beiträge
    1.857

    Standard

    Zitat Zitat von zonky Beitrag anzeigen
    guck dir mal einen Original-Datensatz an - serialisiertes Feld
    Habe ich. Aber das kann ich dem Feld nicht also solches über die CLI übergeben.

    PHP-Code:
    php bin/console contao:content:create   --pid=177   --type=text   --operator=serialize   --set='headline={"unit":"h1","value":"Test"}'   --set='text=<p>Testinhalt</p>'   --set='published=1'   --set='invisible=0' 
    führt nur dazu, dass in dem Überschriftenfeld
    {"unit":"h1","value":"Test"}
    drin steht...
    Jan Theofel
    Barcamp-Moderator für Corporate-Barcamps und öffentliche Barcamps

  9. #9
    Contao-Urgestein Avatar von jan.theofel
    Registriert seit
    23.06.2009.
    Ort
    Berlin
    Beiträge
    1.857

    Standard

    Zitat Zitat von Creasign Beitrag anzeigen
    Kurzes Update zu der Pakete-Familie:
    Vorschlag für das nächste Update:
    In vendor/webwerkwien/contao-ai-core-bundle/src/Command/ContentCreateCommand.php folgende Anpassung ab Zeile 46:

    PHP-Code:
            // if (\array_key_exists('headline', $fields) && \is_string($fields['headline'])) {
            //    $fields['headline'] = serialize(['unit' => 'h2', 'value' => $fields['headline']]);
            //}
            
    if (\array_key_exists('headline'$fields) && \is_string($fields['headline'])) {
              
    $unit $fields['headline_unit'] ?? 'h2';
              unset(
    $fields['headline_unit']);
              
    $fields['headline'] = serialize(['unit' => $unit'value' => $fields['headline']]);
            } 
    Dann geht das per CLI mittels:

    Code:
    php bin/console contao:content:create \
      --pid=177 \
      --type=text \
      --set="headline=Testüberschrift mit H1" \
      --set="headline_unit=h1" \
      --set="text=<p>Testinhalt</p>" \
      --set="published=1" \
      --set="invisible=0"
    Oder ein allgemeiner Weg um serialisierte Inhalte angeben zu können. Das ist ja nicht die einzige Stelle, die davon betroffen ist.
    Jan Theofel
    Barcamp-Moderator für Corporate-Barcamps und öffentliche Barcamps

  10. #10
    Contao-Nutzer
    Registriert seit
    06.10.2011.
    Ort
    Wien
    Beiträge
    97

    Standard

    Servus Jan! Umgesetzt in v0.2.3. Deine Idee mit dem Begleitfeld wurde aufgegriffen und gleich generisch für alle inputUnit-Felder gebaut (also auch News).

    Code:
    php bin/console contao:content:create \
      --pid=177 --type=text \
      --set="headline=Testüberschrift mit H1" \
      --set="headline_unit=h1" \
      --set="text=<p>Testinhalt</p>" \
      --set="published=1" --set="invisible=0"
    Das <feld>_unit-Begleitfeld steuert die Ordnung (validiert gegen h1–h6; ohne Angabe Default h2 bei Content, h1 bei News). Alternativ geht der Wert auch direkt als JSON:

    Code:
    --set='headline={"unit":"h1","value":"Testüberschrift"}'
    Beides gilt für content:create/content:update und news:*; bei einem Update bleibt eine vorhandene Unit erhalten, wenn du nur den Text änderst. news:create hat zusätzlich eine --unit-Option.

    Info zu #8: --operator ist der Audit-/Benutzer-Kontext fürs Versioning, keine Serialisierungs-Option. Die brauchst du hier nicht.

    Danke für den konkreten Vorschlag, das hat die Umsetzung beschleunigt!

  11. #11
    Contao-Nutzer
    Registriert seit
    06.10.2011.
    Ort
    Wien
    Beiträge
    97

    Standard

    Hallo!

    Ich muss meine Antwort aus Beitrag #10 korrigieren — für News war sie leider falsch.

    tl_news.headline ist kein inputUnit-Feld, sondern ein reines Textfeld — es ist der
    News-Titel. Contaos DCA im news-bundle:

    Code:
    'headline' => array(
        'inputType' => 'text',
        'eval'      => array('mandatory'=>true, 'maxlength'=>255, ...),
        'sql'       => "varchar(255) NOT NULL default ''"
    ),
    Contao liest den Wert unverändert (NewsFeedListener, InsertTag news_title). Ein
    serialisiertes {value,unit} landet dort also 1:1 als Titel — im Backend-Listing, im
    Feed und im Frontend steht dann a:2:{s:5:"value";...}.

    Betroffen ist alles, was mit contao:news:create bis v0.2.3 angelegt wurde,
    inklusive der --unit-Option aus #10.

    Behoben in v0.2.4:
    - news:create schreibt Klartext, --unit ist entfallen
    - news:read gibt den Wert roh zurück (die Deserialisierung hatte den Fehler maskiert)
    - neuer Reparatur-Command für Altbestände:

    Code:
    composer update webwerkwien/contao-ai-core-bundle
    php bin/console contao:news:repair-headlines --dry-run
    php bin/console contao:news:repair-headlines
    Der Command entpackt serialisierte Headlines zum reinen Titel, ist idempotent und
    lässt alles unangetastet, was kein {value,unit}-Payload ist. --dry-run zeigt vorab,
    was sich ändern würde.

    Für Content-Elemente bleibt alles wie in #10 beschrieben — tl_content.headline
    ist tatsächlich ein inputUnit-Feld:

    Code:
    php bin/console contao:content:create \
      --pid=177 --type=text \
      --set="headline=Testüberschrift mit H1" \
      --set="headline_unit=h1" \
      --set="text=<p>Testinhalt</p>" \
      --set="published=1" --set="invisible=0"

    Liebe Grüße!

  12. #12
    Contao-Nutzer
    Registriert seit
    06.10.2011.
    Ort
    Wien
    Beiträge
    97

    Standard Update zur Paketfamilie

    Servus! Kurzes Update zur Paketfamilie — die vergangene Woche hat einiges gebracht.


    contao-ai-core-bundle — v0.2.7 -> v0.2.16

    • record:clone hat jeden tinyint-Wert auf 1 gekappt (v0.2.15). Alle vier Cloner betroffen, also auch News, Events und FAQ — und das bei status: ok. Dazu unten mehr.
    • Löschen kaskadiert jetzt und landet als ein Eintrag im Papierkorb (v0.2.8/v0.2.9). Vorher blieben Kinddatensätze als Waisen zurück.
    • unpublish schrieb '' in eine tinyint-Spalte und flog auf Servern mit striktem SQL-Modus (v0.2.10).
    • Schreibzugriffe tauchten nie im Systemlog auf (v0.2.11–v0.2.13). Jetzt eine Zeile je Vorgang unter System ? Systemlog, Herkunft "Kommandozeile" (v0.2.14).
    • --operator wirkt auch bei version:restore und template:write, damit die Zuordnung stimmt (v0.2.14).
    • Datei-Referenzen (fileTree) kamen beim Lesen als Zeichensalat statt als UUID zurück (v0.2.15).
    • Neu: --ids für Massenänderungen; published und hide sind beim Klonen überschreibbar (v0.2.15).


    Wer schon geklont hat, sollte nachzählen — sinngemäß für eigene Zahlenfelder:

    Code:
    SELECT COUNT(*) FROM tl_page WHERE mein_zahlenfeld > 1;
    Steht dort 0, obwohl es größere Werte geben müsste, sind sie gekappt. Die Versionshistorie der Quelldatensätze hat sie noch.

    Der Merksatz dahinter: tinyint ist in Contao der Ja/Nein-Typ — Doctrine mappt es auf boolean, unabhängig von der Längenangabe. Für Zahlen also smallint(5) unsigned nehmen, so macht es die Core-DCA auch.


    contao-ai-cli — v0.4.1 -> v0.6.0

    • 15 fehlende Schreibbefehle ergänzt (v0.5.0): update und delete für Seiten, Artikel, Inhalte, News, Events und FAQ, dazu page publish.
    • --ids und --ids-from-file auf allen Update-Befehlen (v0.6.0). Ein Feld auf 174 Seiten zu setzen dauerte vorher rund vier Minuten — 1,4 s je Datensatz, davon 0,67 s reiner Verbindungsaufbau. Jetzt eine Verbindung, aber weiterhin eine eigene Version je Datensatz.
    • connect nutzt auf Managed Editions den Composer-Passthrough des Contao Managers, statt allow-plugins in die Projekt-composer.json zu schreiben (v0.4.2).
    • Das Selbstupdate meldete Erfolg, ohne je etwas zu tun (v0.4.3).
    • Der REPL startete nur auf einer Konsole in UTF-8 (v0.4.4). Und jeder Befehl stürzte ab, sobald ein Datensatz ein Zeichen außerhalb von cp1252 enthielt (v0.6.0).
    • health unterscheidet jetzt "Bundle fehlt" von "nicht konfiguriert" (v0.5.1), schlägt keine Downgrades mehr vor (v0.5.2) und nennt die Contao-Version des Ziels (v0.6.0).


    Für --ids braucht es core-bundle v0.2.15 auf dem Ziel.


    contao-ai-backend-bundle — v0.1.3 -> v0.1.5

    • Der Systemlog-Eintrag eines Tool-Aufrufs sagte nicht, welches Tool lief — drei fast gleiche Zeilen je Chat-Runde (v0.1.4).
    • Die Beschreibung des record_clone-Tools behauptete, nicht erlaubte Felder würden stillschweigend verworfen (v0.1.5). Seit v0.2.15 kommen sie als ignored_modifications zurück — und eine Tool-Beschreibung ist das, woraus das Modell seine Schlüsse zieht.



    Update wie gewohnt:

    Code:
    composer update webwerkwien/contao-ai-core-bundle
    composer update webwerkwien/contao-ai-backend-bundle
    pipx install --force git+https://github.com/webwerkwien/contao-ai-cli.git@v0.6.0
    Liebe Grüße!

  13. #13
    Contao-Nutzer
    Registriert seit
    06.10.2011.
    Ort
    Wien
    Beiträge
    97

    Standard

    Servus! Größeres Update — das Backend-Menü ist jetzt durchgehend schreibbar.
    core-bundle v0.2.16 -> v0.2.27, CLI v0.6.0 -> v0.8.7.

    Bisher konnte die Paketfamilie Seiten, Artikel, Inhalte, News, Events und FAQ
    bearbeiten. Alles andere im Backend war lesbar, aber nicht änderbar — Theme-Ebene,
    Rechte, Einstellungen, Papierkorb, die Elterntabellen, Formulargenerator und
    Newsletter. Das ist jetzt geschlossen.

    Dazu record list und record schema für jede Tabelle mit einer DCA, auch aus
    Erweiterungen. Tabelle, Spalten, Filter und Sortierung werden serverseitig
    geprüft — einen Spaltennamen zu raten ist also gefahrlos, es scheitert laut
    statt still.

    Zwei Dinge zum Nachsehen

    1. contao:dca:schema gab bei Auswahlfeldern die falschen Werte zurück
    (behoben in v0.2.21). Statt der Optionswerte kamen die Array-Indizes:

    Code:
    tl_page.sitemap  ->  [0, 1, 2]
    deklariert ist    ->  map_default, map_always, map_never
    Betroffen waren 63 von 66 Optionslisten im Kern. Wer sich auf dca:schema verlassen hat, um gültige Werte zu ermitteln, sollte
    die betroffenen Stellen einmal nachsehen.

    2. Ein --set mit einem Feldnamen, den es nicht gibt, wird jetzt abgewiesen
    (v0.2.27). Vorher kam:

    Code:
    --set gibtesnicht=1  ->  {"status":"ok","updated":["gibtesnicht"]}
    Geschrieben wurde nichts. Contao verwirft beim Speichern, was keine Spalte ist —
    gemeldet wurde trotzdem Erfolg. Ein Tippfehler im Feldnamen las sich damit als
    erfolgreiche Änderung.

    Der Newsletter verschickt nicht — mit Absicht

    newsletter send gibt es als Befehl, und er lehnt immer ab. Zwei Gründe:

    Contaos Versand ist an den Browser gebunden. Jeder Zyklus endet mit einem
    JavaScript-Timer, der das nächste Paket nachlädt — das Handbuch sagt
    ausdrücklich, man dürfe das Fenster nicht schließen. Es gibt also nichts, was
    sich an eine Konsole durchreichen ließe. Und eine verschickte Mail holt kein
    Backup zurück.

    Wichtig für alle, die auf die Idee kommen könnten, das über die Datenbank
    abzukürzen: tl_newsletter.sent auf 1 zu setzen verschickt nichts. Es
    markiert den Newsletter als versendet und veröffentlicht ihn im Frontend-Archiv,
    weil der Reader genau auf dieses Feld filtert. Das Bundle weist Schreibzugriffe
    auf sent und date deshalb ab.

    Anlegen, Ändern und Löschen von Kanälen, Newslettern und Empfängern geht
    vollständig. Empfänger folgen dabei den Regeln von Contaos eigenem CSV-Import:
    gültige Adresse, keine Dublette im Kanal, und nicht auf der Sperrliste des
    Kanals. Wer über die CLI anlegt, muss das Aktivieren ausdrücklich angeben —
    Double Opt-in schützt die Selbstanmeldung im Frontend, nicht die Tabelle, und
    die Einwilligung liegt damit beim Betreiber.

    Dazu eine Reihe weiterer Bugfixes in beiden Paketen — Details in den CHANGELOGs.

    Update wie gewohnt

    Code:
    composer update webwerkwien/contao-ai-core-bundle
    pipx install --force git+https://github.com/webwerkwien/contao-ai-cli.git@v0.8.7
    Die CLI setzt für die neuen Gruppen core-bundle v0.2.27 auf dem Ziel voraus.
    contao-ai-backend-bundle ist unverändert bei v0.1.5.

    Liebe Grüße!

Aktive Benutzer

Aktive Benutzer

Aktive Benutzer in diesem Thema: 2 (Registrierte Benutzer: 0, Gäste: 2)

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •