External integrations in Gladys Assistant

New SDK version, v0.8.0 with a new « section » field, and mandatory documentation link on the integration page

Edit: Template updated for v0.8.0

Attention, the store has been updated and is now stricter, it is now mandatory to have documentation in the integrations :warning:

Don’t forget to run :

npx github:GladysAssistant/integration-store

To check if your integration passes validation, and correct your repo if necessary

(pass this message to Claude)

New SDK version: v0.9.0!

Here’s what’s new:

  • Management of one-way « communication » type integrations (FreeMobile, Callmebot, ntfy.sh, etc…)
  • Management of Gladys Plus webhooks for Netatmo type integrations that require a Cloud webhook

Ok, I’ve updated the Gladys PR with 3 changes:

1. « Your device isn’t on the list? » banner — it now highlights Matter and community external integrations: « anyone can create one and publish it in the store, it then appears in this list »,

2. Announced deprecation of Tuya, MELCloud, Telegram, and Netatmo — I did both to make it unambiguous:

  • a red « Soon to be deprecated » badge on their catalog card (flag deprecated in the integration JSONs, rendered in IntegrationTags);
  • a warning at the top of each of the four integrations’ page (shared component DeprecationWarning): « will soon be deprecated in favor of an equivalent external integration… both versions will coexist in the catalog during the transition — you can continue to use this one for now ».

3. Authentication errors on restart (close code 4000) — diagnosis confirmed, and it was even worse than that: without an env var JWT_SECRET, the secret is regenerated at every Gladys boot, and as start() restarted the existing container with the JWT token frozen in its env (signed with the old secret), the integration looped on the refusal without ever self-repairing. Two fixes:

  • the supervisor now signs integration JWTs with its own secret, generated once and persisted as a variable (EXTERNAL_INTEGRATION_JWT_SECRET) — it survives restarts and backup restorations, in line with the containers it validates;
  • self-repair in start(): before restarting an existing container, verifyContainerToken inspects the token in its env (signature with the current secret + correct service + correct token_version); if it’s expired, the container is recreated with a fresh token instead of being restarted for nothing. This also fixes, from the next boot, containers created before this fix.

Here’s the simplicity of creating an integration :joy:

For info @cicoub13 @Terdious @Lokkye:

[
  {
    "store_slug": "callemand/gladys-airzone-cloud",
    "level": "error",
    "reason": "docker_image: image is not publicly pullable (registry auth denied, HTTP 403)",
    "checked_at": "2026-07-23T15:30:08.198Z"
  },
  {
    "store_slug": "cicoub13/gladys-tp-link",
    "level": "error",
    "reason": "docs/en.md: file not found — user documentation is mandatory",
    "checked_at": "2026-07-23T15:30:08.198Z"
  },
  {
    "store_slug": "Terdious/gladys-netatmo",
    "level": "error",
    "reason": "docs/en.md: file not found — user documentation is mandatory",
    "checked_at": "2026-07-23T15:30:08.198Z"
  },
  {
    "store_slug": "Terdious/gladys-tuya",
    "level": "error",
    "reason": "docs/en.md: file not found — user documentation is mandatory",
    "checked_at": "2026-07-23T15:30:08.198Z"
  }
]

Source: https://integration-store-storage.gladysassistant.com/rejected.json

The documentation is now displayed in the interface:

If I click on « Documentation »:

I must say I’m impressed by the deployment speed of this new system, the number of integrations already available, and the simplicity at all levels:

  • Development,
  • Deployment,
  • Updates,
  • Device integration.

Of course, this would have been impossible at such a pace without AI. But the decision-makers (@pierre-gilles) and the prompters have a lot to do with it!!

The coming months are very promising on this front ^^

@pierre-gilles how does the backup of external integrations work if we want to migrate to a new PC, for example?

How to handle the above cases when there is no data to save, so the « Save Configuration » button is useless

I will also add recommendations on choosing Docker images to avoid using large images. Preference for Alpine, which is ultra-light and widely used for our use case.

This brings me to another question. Shouldn’t Gladys also check if the image being used is not too old or subject to security vulnerabilities? Just some information before installing the integration.
We can also add the size of the image as well.

Thanks @Terdious for all your developments, I must say I’m also very impressed by the speed of development we can achieve, it’s crazy it’s going to revolutionize the project :slight_smile:

This weekend, I was in the mountains without a network, and yet 13 integrations were able to be published on the store, unthinkable in the old integration system ^^

It’s cool, we’re going to start with a store already filled!

The installations will be automatically reinstalled, as all data is stored in the database :slight_smile:

Here is the exact process explained by Claude:

What is in the backup. The Gladys Plus backup is a tar.gz containing the SQLite database (+ the DuckDB folder) — and everything that defines an external integration is in the database: the t_service line (Docker image, manifest, store_slug, version, token_version, status), the configuration (variables scoped to the service, including secrets and OAuth tokens), the devices, the granted hardware classes, the contact profiles, and the supervisor’s JWT secret (EXTERNAL_INTEGRATION_JWT_SECRET, persisted in a variable precisely to survive restorations).

What happens on startup on the new machine.

  1. init() reconciles the containers by Docker label — the code comment specifically cites the restore case: the container_id in the database are obsolete; as no container exists on the new PC, they are set to null (externalIntegration.init.js:70-84).
  2. The integrations then start with the standard service lifecycle. In start(), no container_idcreateIntegrationContainer: the Docker image is re-downloaded from the registry, a new container is created with a freshly signed JWT (valid, since the secret and the token_version come from the restored database), the private network and sub-containers are recreated, and the config is pushed back to the integration upon connection.
  3. The rule « STOPPED = ignored at boot » applies as for internal services: an integration stopped before the backup remains stopped, without being uninstalled.

The two limits to know.

  • Obviously, you need Docker and network on the new machine: the images are not in the backup, they are re-pulled (an integration would go to ERROR if the registry is unreachable, and restartable afterwards).
  • The /data folder is not backed up. Each integration has a bind <base>/external-integrations/<selector> → /data (and the volumes of the sub-containers live below). The doctrine is that integrations should be stateless (states live in Gladys), so in practice it shouldn’t break anything — but an integration that stores a local state (or a sub-container type broker with persistence) starts from scratch. If we want to cover this one day, we would need to include this folder in the backup, with the question of the size to cut.

Well spotted! I’ll fix it.

This is the case of the default template, I recommend the Node-Alpine image which is super light :slight_smile:

I think that, for a V1, the current proposal is sufficient.

If a user is technically savvy enough to look for this type of information, they will already find it on the integration’s GitHub repository, which is referenced.

I also think we should avoid getting into too technical details. The goal of Gladys is to offer a clean, public-friendly product, with as little jargon as possible.

External integrations were precisely designed to be transparent: the user is hardly aware that an external container is running. The experience is deliberately very close to that of Gladys’s native integrations today :slight_smile:

I’m making really fast progress today! :tada:

I’ve already merged into the master branch of the Gladys repository:

  • The technical specification of the development.
  • The entire implementation.

I then published a new development image:

gladysassistant/gladys:dev

I deployed it on my production instance. I’ve already migrated my MelCloud integration to the new system and I’m in the process of doing the same for Telegram.

The goal is to validate all this in real conditions for a few days. If everything goes well, the feature will be released this week.

I’m quite confident, so far so good!

I’m so far behind, it’s been 15 days since I was really available… it’ll take me a while to catch up on all this (even just this thread), you guys are amazing (in the best sense of the word)

:joy::joy: I’m going to share this image on X

Well, I’m super happy about the external integrations at my place!!

I think I’m going to release on Thursday evening! :fire:

There you go, the documentation has been adapted to display the catalog on the site!

On this page:

Already 20 external integrations! :exploding_head:

When you consider that we’ve only had 36 internal integrations in 6 years of Gladys v4, this is already an incredible pace. And I think it’s only going to accelerate as we convince more developers to contribute.

I really think we’ve got something here!! :grinning_face_with_smiling_eyes:

Release TOMORROW NIGHT :fire:

:star_struck: well, I couldn’t help but read the 4.84.0 release notes on the blog and it’s awesome :grimacing:

Quick question about the internal integrations, which now exist externally and continue in parallel: is there/will there be an « automatic switch » tool from internal to external?
For example, with Telegram, my info is on the internal, I click a button and everything moves to the external and deactivates the internal? (oh yes, I’m lazy!! :rofl:)

Hi @mutmut! Thanks for your message!! :grinning_face_with_smiling_eyes:

No, there is no automatic switch. But I assure you, it’s really very simple:

You go to the current Telegram integration, you copy your token, you deactivate the integration, then you install the new external integration, you paste your token and you follow the pairing process. :blush:

I admit that I prefer that you (the power users of Gladys) go through the “classic” installation process that all users will follow later. This will allow us to get real user feedback on the installation of external integrations and improve the process if needed. :grinning_face_with_smiling_eyes: