Contao-Summit 2026
Ergebnis 1 bis 11 von 11

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
    95

    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
    95

    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
    95

    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.582
    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
    95

    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
    95

    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!

Aktive Benutzer

Aktive Benutzer

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

Berechtigungen

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