External integrations in Gladys Assistant

Statut : brouillon, ouvert au débat
Discussion : ce sujet du forum


Salut à tous,

Je vous propose une nouvelle fonctionnalité qui va changer la manière dont les intégrations sont développées dans Gladys.

C’est un projet longuement mûri, et je serais ravi d’avoir vos retours, vos idées et vos remarques pour continuer à l’améliorer :slight_smile:

Pourquoi maintenant

Depuis le début du projet, toutes les intégrations de Gladys vivent dans le core. N’importe qui peut en développer une ou l’améliorer via une pull request, mais chaque ligne passe par ma review avant d’être mergée. Ce choix a un énorme avantage : quand vous installez Gladys, tout est déjà là. Pas de store, pas de dépendances à gérer, pas de plugin cassé après une mise à jour. C’est une des raisons pour lesquelles Gladys est plus simple à prendre en main que d’autres solutions.

Mais ce modèle a un plafond, et je suis en train de le toucher. Il existe des milliers de marques, de protocoles, de services, et la moindre modification d’une intégration, même un simple changement de traduction, doit passer par moi : review, merge, release. Ça ne passe pas à l’échelle, et ça fait de moi le goulot d’étranglement du projet.

On pourrait se dire que Matter va résoudre ce problème. Matter arrive, et va à mon avis devenir le protocole de référence qui contrôlera tous les appareils connectés à l’avenir : un seul standard, tous les appareils compatibles nativement, plus besoin d’une intégration par marque. Sauf qu’on ne sait pas quand cet avenir sera une réalité, et le projet ne peut pas se permettre d’attendre indéfiniment que le parc installé bascule.

Et surtout, Matter ne couvre que le contrôle des appareils connectés. Il reste tout un pan d’intégrations qui n’a rien à voir avec des appareils : la communication (Telegram, etc.), la météo (OpenWeather, Météo France), les calendriers (CalDAV, Google Calendar)… Tout ça ne passera jamais par Matter. Si on veut que Gladys devienne un projet avec la même ambition que Home Assistant, on doit pouvoir permettre l’installation d’intégrations externes.

Cette RFC propose donc d’ouvrir Gladys aux intégrations externes : des intégrations développées et publiées par n’importe qui, sans validation préalable de ma part, installables en un clic depuis l’interface.

Le défi, c’est de faire ça sans sacrifier ce qui fait Gladys. Concrètement, quatre exigences non négociables ont guidé cette proposition :

  1. Une intégration qui plante ne doit jamais faire planter Gladys.
  2. Pas d’états incompréhensibles : si une intégration ne répond plus, l’utilisateur doit le voir et pouvoir agir.
  3. Les interfaces doivent rester propres et cohérentes entre elles.
  4. Zéro manipulation technique pour l’utilisateur. Pas de terminal, pas de YAML, pas de redémarrage manuel.

Ce que cette RFC ne propose pas

  • On ne remplace pas les intégrations natives. Les intégrations des protocoles universels (Matter, Zigbee, Z-Wave…) resteront toujours dans le core, pré-installées, maintenues comme aujourd’hui. Le nouveau système s’ajoute à côté, et vise toutes les intégrations de protocoles ou de services qui ne sont pas universels : désormais, n’importe qui pourra créer une intégration séparée.
  • On ne vise pas la compatibilité avec les intégrations Home Assistant / HACS. Elles sont profondément couplées à l’architecture de HA ; les exécuter dans Gladys est irréaliste. En revanche, je m’inspire de leur modèle de distribution (dépôt Git + manifeste + store).
  • On ne permet pas aux intégrations d’injecter du code dans l’interface. C’est un choix assumé, détaillé plus bas.

Architecture proposée

Un conteneur Docker par intégration

Gladys tourne déjà exclusivement dans Docker, avec la socket Docker montée. On s’appuie dessus : chaque intégration externe tourne dans son propre conteneur, créé et supervisé par le core Gladys.

Ce conteneur est verrouillé au maximum :

  • pas de mode privilégié, pas d’accès à la socket Docker
  • pas d’accès à la base de données ni aux fichiers de Gladys
  • système de fichiers en lecture seule, sauf un petit répertoire de données qui lui est propre
  • limites strictes de mémoire, CPU et nombre de processus
  • réseau restreint aux hôtes que l’intégration a déclarés dans son manifeste.

Une intégration qui crashe, qui fuit de la mémoire ou qui part en boucle infinie reste confinée dans sa boîte. Et une intégration malveillante ou mal écrite ne peut pas « aller modifier la base en direct » : le fichier SQLite n’existe tout simplement pas dans son système de fichiers.

Ce choix apporte un bonus important : les intégrations ne sont plus limitées à Node.js. Une image Docker peut contenir du Python, du Go, du Rust. Chaque auteur embarque ses dépendances dans son image, et tout le build est fait en amont, au moment de la publication, jamais au runtime chez l’utilisateur.

À terme, ce choix apporte aussi quelque chose d’intéressant : il sera possible de faire tourner des intégrations déportées !

Toute communication passe par l’API-hôte

Une intégration ne touche jamais les internals de Gladys. Sa seule porte d’entrée est une API-hôte : l’intégration dialogue avec le core via une API REST HTTP JSON toute simple, dans le même esprit que ce qui existe déjà dans Gladys aujourd’hui.

Les primitives envisagées pour la v1 :

  • déclarer des appareils et leurs fonctionnalités, dans le modèle device/feature existant de Gladys ;
  • publier des états et recevoir des commandes
  • stocker sa configuration et ses secrets (stockés en DB côté core)
  • écrire des logs structurés
  • demander une découverte réseau médiée : c’est le core, qui a accès au réseau de l’hôte, qui effectue les scans mDNS et le passthrough des périphériques USB, puis transmet les résultats. L’intégration n’a ainsi jamais besoin du mode host ni d’accès matériel direct.

Ce contrat au niveau du protocole est le vrai fondement de la proposition. Le conteneur n’est « que » le mécanisme qui rend ce contrat impossible à contourner. Il permet aussi de faire évoluer le schéma interne de Gladys sans casser l’écosystème : tant que l’API-hôte est stable, les intégrations continuent de fonctionner.

Supervision : pas d’états zombie

Le core embarque un superviseur qui gère le cycle de vie complet de chaque intégration, avec une machine à états toujours visible dans l’interface :

Installée → Démarrage → En fonctionnement → Dégradée → En panne → Arrêtée

Le superviseur envoie un heartbeat régulier à chaque intégration. Pas de réponse ? L’intégration passe en « Dégradée » et est redémarrée automatiquement, avec un délai croissant entre les tentatives. Si elle crashe en boucle, on arrête d’insister : elle passe en « En panne », et l’utilisateur voit un message clair avec les logs de l’intégration et les actions possibles (redémarrer, désactiver, signaler au développeur).

Tous les appels entre le core et l’intégration ont un timeout. Une intégration qui pend ne bloque jamais Gladys.

L’objectif : qu’il n’existe plus aucun état non observable ou non récupérable. Quand quelque chose ne va pas, on le voit, on comprend, on agit, depuis l’interface.

Interface : déclarative, pas de code arbitraire

C’est probablement le choix le plus discutable de cette RFC, donc autant l’assumer clairement.

Les intégrations ne fournissent pas de composants d’interface. Elles décrivent leurs besoins, et c’est Gladys qui rend l’interface avec son propre design system :

  • la configuration est décrite par un schéma (type JSON Schema) : Gladys génère le formulaire, la validation, les messages d’erreur, de façon identique pour toutes les intégrations ;
  • les appareils sont déclarés dans le modèle device/feature existant : ils s’affichent automatiquement avec les mêmes cartes et les mêmes contrôles que les intégrations natives ;
  • pour les besoins plus spécifiques, un vocabulaire de widgets déclaratifs sera défini et enrichi progressivement, en fonction des besoins réels remontés par les développeurs.

Ce que ça coûte : un développeur ne pourra pas créer un écran totalement sur mesure. Ce que ça garantit : une interface cohérente partout, aucune faille XSS venue d’un plugin, aucun conflit de versions front, et une expérience identique pour l’utilisateur quelle que soit l’origine de l’intégration. Vu les priorités du projet, je pense que c’est le bon compromis. Mais c’est exactement le genre de point sur lequel j’attends vos retours.

Distribution : un store dans Gladys

L’utilisateur découvre et installe les intégrations depuis un store intégré à l’interface. Installer = un clic. Le core télécharge l’image, la vérifie, lance le conteneur, affiche le formulaire de configuration si l’intégration a besoin d’identifiants. Aucun terminal, aucun fichier à éditer.

Chaque intégration est publiée avec un manifeste : nom, version, versions de Gladys compatibles, permissions demandées (hôtes réseau, périphériques), schéma de configuration. Les permissions sont affichées à l’utilisateur avant l’installation, comme sur un store mobile.

Toutes les intégrations externes sont « community based » : je ne prévois pas de les relire une par une, ce serait retomber dans le goulot d’étranglement que cette RFC cherche justement à supprimer. Un avertissement clair est affiché à l’installation pour rappeler qu’il s’agit de code tiers non audité. C’est le rôle des permissions déclarées et de l’isolation par conteneur de rendre cette ouverture acceptable.

Développer une intégration à l’ère de l’IA

Un point qui change tout par rapport à il y a quelques années : développer une intégration est devenu très facile grâce à l’IA. Mon intention est de fournir un template d’intégration officiel, propre et documenté. À partir de ce template, avec Claude Code/Cursor, créer une intégration pour un service ou un protocole donné devient l’affaire de quelques heures plutôt que de quelques jours.

C’est ce qui rend cette proposition réellement puissante : au lieu d’attendre que je développe ou que je relise chaque intégration, la communauté pourra en produire beaucoup plus, beaucoup plus vite.

Le rythme d’apparition de nouvelles intégrations ne sera plus limité par ma disponibilité.

Feuille de route proposée

  1. Définir l’API-hôte et le SDK, puis proposer à quelques développeurs de créer les premières intégrations externes dessus.
  2. Spécifier le manifeste et le schéma d’interface déclarative.
  3. Implémenter le superviseur et le lancement de conteneurs verrouillés, en preuve de concept sur une seule intégration.
  4. Construire le store et le parcours d’installation, avec le template d’intégration officiel.
  5. Ouvrir la publication à tous.

Mon objectif est de sortir ce nouveau système le plus vite possible : avec les IA, il est possible d’aller très vite.

Je compte commencer le travail dès cette semaine avec Fable 5, tant qu’il est disponible.

Questions ouvertes à la communauté

  • Le compromis « UI déclarative uniquement » vous semble-t-il acceptable ? Quels cas d’usage réels ne rentreraient pas dedans ?
  • Quelles primitives manquent à l’API-hôte pour vos intégrations rêvées ?
  • Faut-il limiter la v1 aux intégrations en Node.js (avec un SDK officiel) pour simplifier, ou ouvrir tous les langages dès le départ ?

Cette proposition est un point de départ, pas une décision gravée dans le marbre : vos critiques, vos objections et vos idées sont exactement ce que j’attends pour la rendre meilleure :slight_smile:

Hello @pierre-gilles,

I’m not an expert in home automation, but I’m of course very happy to hear about this possibility of custom integration to meet specific needs!

I assume that if an extension is highly relevant and in high demand, it will eventually be integrated into the Gladys core?

Will there be any performance issues with having a hundred Docker containers going through a single API Host channel?

I’ve been using Gladys for less than two months, but I’m amazed by its responsiveness and the speed of its development!

Thanks again!

It’s indeed a big change but I also think it’s necessary. You alone can’t develop, review, and maintain all the integrations even with AI. Even with super contributors, reviewing contributions surely takes you a lot of time.

Also, even if it’s to be preferred, we must also recognize that the MatterBridge integration can have its limits when the Matter protocol doesn’t support certain features.

I agree with your approach of clearly separating the core and the integrations. Not allowing integrations to access the system is also a very good point. I would also specify that integrations must be free and open source to be accepted.

As for a v1 version, I would add the Python language, which is widely used in home automation and easy to pick up. Moreover, AI agents work very well for generating Python code.

Good question, but don’t worry: the API is not a single queue where requests are processed one by one. It’s an HTTP server, exactly like the one Gladys already exposes today for the frontend.

Since Node is asynchronous, while a request waits for the database, the event loop processes many others in parallel. 100 containers hitting it is a ridiculous load.

The real point of attention isn’t the API; it’s the RAM. A container itself weighs almost nothing (it’s not a VM), but each Node process carries the V8 runtime, so you need to account for 50-80 MB of RAM used per integration depending on what it does. With a dozen integrations, no problem on a mini-PC. With a hundred running simultaneously, that depends on your available RAM :smiley:

In practice, most installations will have between 5 and 20 external integrations, which is totally comfortable on most mini-PCs.

Thanks!!

Anyway, the API will be fully open and documented, so each developer can use it as they wish :wink:

The real issue is more about what examples we provide and in which languages. Personally, I don’t have any experience with Python, so I might have an AI generate an example, but I wouldn’t really be able to review it, validate it, or effectively help users with it.

But that’s the strength of these external integrations: everyone will be free, and I won’t be the bottleneck :smiley:

For the future integration store, I want to go with a fully decentralized architecture, without manual validation, without review, and without needing permission to publish.

In concrete terms, each developer will simply publish their integration in their own GitHub repository by adding a specific topic. This repository will remain the source of truth: everyone keeps control of their code and their updates.

On the other hand, a fully automatic indexer (a public GitHub Action) will regularly scan all repositories with this topic. It will only check objective criteria: presence of a valid manifest, adherence to the schema, accessibility of images, version consistency, etc. If everything is compliant, the integration will be automatically added to a static index.json, which will then be distributed via GitHub Pages and a CDN.

Gladys instances will only download this static index, ensuring high performance, avoiding GitHub API limitations, and making it easy to cache the content. And even if the indexer becomes unavailable, the last published index will continue to work.

The goal is simple: no one needs my approval to publish an integration. The only rules are those automatically checked by the script, whose code will also be public. Thus, everyone will be able to immediately understand why their integration is indexed… or why it is not.

Well, I didn’t understand everything :face_with_head_bandage:, but I think the idea is excellent because it will allow Gladys to make a leap forward in terms of its ability to compete with HA. And this will allow everyone to contribute « easily » to improving Gladys, which will keep its core intact!

It would be great to eventually allow the choice to use another Git hosting platform like GitLab and Codeberg.

Hi @contributors :waving_hand:

I made great progress on this topic today! I spent the day writing the technical specification with Fable 5.

The implementation specification is available here:

My goal is to advance this development quickly, while maintaining a high level of quality.

As always, all your feedback is welcome. :slightly_smiling_face:

3 new repositories created:

Implementation in progress by 3 Fable 5 agents:

I’m getting ahead because Fable 5 is not guaranteed to stay after July 19th.

If you have any feedback, of course everything is still modifiable, I’m really open to feedback!

I think it’s a good thing that integrations can be managed this way.

No language barrier and time saved on your side, as validating each PR takes a lot of time, especially right now with AI.

However, concretely, if we take the example of the Meteo France integration, there is the API part to manage with the integration, but also the widget part and the scene trigger and scene action.
Should we split it into several parts to separate the integration part from the widgets and scene part? There would therefore be a PR for the core with the widgets/scene and the Meteo France integration part for the Gladys store?

And what about the existing integrations? Should they move to the store or will you keep them?

In the long run, I think many integrations can be moved out of the core, but it’s important to clearly state what belongs to the core and what is external. Since external integrations cannot access the hardware, we can already say that the core handles « protocols » like Zigbee, Z-Wave, and Matter because we need to access the USB dongles. The user interface and the supervisor are also part of the core. A list with explanations would be welcome.

To add a new language more easily, I propose two things:

  • Provide a « JSON Schema » to validate the structure of JSON messages
  • A Docker server that allows validating an SDK. The idea would be as follows:
    • I develop an SDK in language X based on the official JS version with the same validation tests
    • Once development is complete, I launch the SDK validation server
    • I run the validation tests by connecting to the server
    • My SDK is validated when 100% of the tests are valid
      This method also allows automating development and validation by an AI agent.

Another point is how much we need to limit the resources of external integrations to avoid having monsters and breaking the Gladys experience. Depending on the languages, this can range from simple to triple in terms of memory and CPU load. If we’re too strict, we close the door to many interpreted languages (Python, Ruby, and even JS with NodeJS), and if it’s too loose, we’ll need a machine with a lot of RAM. So, goodbye to machines like Raspberry Pis, NAS, Freebox, etc. Plus, RAM is now very expensive.
As a C/C++ developer, I’m more on the strict side :slight_smile: