# Permettre aux intégrations externes de déclarer leur propre déclencheur/actions de scènes

**URL:** <https://community.gladysassistant.com/t/permettre-aux-integrations-externes-de-declarer-leur-propre-declencheur-actions-de-scenes/10870>\
**Category:** Demandes livrées\
**Tags:** feature-core, in-progress\
**Created:** [Septembre 18, 2026, 7:50 UTC](https://community.gladysassistant.com/t/permettre-aux-integrations-externes-de-declarer-leur-propre-declencheur-actions-de-scenes/10870 "2026-09-18T07:50:56Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [Septembre 18, 2026, 7:50 UTC](https://community.gladysassistant.com/t/permettre-aux-integrations-externes-de-declarer-leur-propre-declencheur-actions-de-scenes/10870/1 "2026-09-18T07:50:56Z")

</div>

Les intégrations externes devraient pouvoir déclarer des déclencheurs et des actions de scènes, pour pouvoir étendre Gladys sans mise à jour du core.

---

<div class="post-metadata">

**Author:** ![cursor-bot](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/cursor-bot/32/22252_2.png) [@cursor-bot](https://community.gladysassistant.com/u/cursor-bot)\
**Post date:** [Septembre 18, 2026, 8:07 UTC](https://community.gladysassistant.com/t/permettre-aux-integrations-externes-de-declarer-leur-propre-declencheur-actions-de-scenes/10870/2 "2026-09-18T08:07:24Z")

</div>

Salut tout le monde !

Ce sujet est désormais **en cours de développement**.

Une PR a été ouverte pour spécifier les déclencheurs et actions de scènes déclarés par les intégrations externes :

> <https://github.com/GladysAssistant/Gladys/pull/3110>
>
> \### Description
> 
> Spec-first PR (no code): adds \`docs/specs/external-integrations…/capabilities/scene-triggers-and-actions.md\`, a self-contained capability file of the external integrations living spec, following the folder's rules (one file per capability, owns its manifest field, endpoints, WebSocket messages, SDK surface, frontend behavior, tests and manual verification; no new section identifier, nothing edited in the shared \`contracts/\` tables).
> 
> What the spec defines:
> 
> \- \*\*Manifest\*\*: two optional top-level fields, \`scene\_triggers\` and \`scene\_actions\` (1–20 each), declarable by every integration type. Triggers carry \`fields\` (filters, same flat format as \`config\_schema\`, restricted type list) and \`variables\` (whitelist of the event data exposed to the scene). Actions carry \`fields\`, \`timeout\_seconds\` (5–120) and \`outputs\` (whitelist of the values returned to the scene). Keys are permanent.
> \- \*\*Core scene engine\*\*: one generic trigger type \`external-integration.scene-event\` and one generic action type \`external-integration.scene-action\`, both carrying the integration selector and the declared key, with \`fields\` nested (stored shapes given). Matching is deliberately simple: equality / \`multi\_select\` membership on declared fields, empty = wildcard; thresholds and operators stay on device features. Actions template \`string\` fields, validate against the declaration at execution time, relay through the proxy service (\`scene.runAction\`) and write whitelisted \`outputs\` into the scope. The manifest is consulted at execution time, never at save time, so scenes load and save even when the integration is gone.
> \- \*\*Host API\*\*: \`POST /api/integration/v1/scene/event\` \`{ key, data }\` — flat bounded data, whitelisted against the declaration, \`404\` on an undeclared key, 60 events/min per integration. REST rather than a fire-and-forget WS message because the payload can be wrong and the integration must get a \`4xx\`.
> \- \*\*WebSocket\*\*: \`external-integration.scene-action.run\` \`{ message\_id, key, fields }\` → \`command-result\` \`data.outputs\`, ack within the declared \`timeout\_seconds\`.
> \- \*\*Frontend\*\*: a new read-only \`GET /api/v1/external\_integration/scene\` (every authenticated user, literal route before \`:selector\`), a dynamic "Integrations" category in both type pickers, trigger/action cards rendered by the existing \`ConfigField\` engine (string fields of actions use the variables-aware input), orphan/stopped cards flagged honestly and never edited behind the user's back, an informational line on the install screen.
> \- \*\*Lifecycle, security, SDK\*\* (\`publishSceneEvent\`, \`onSceneAction\`), template demo declarations, developer-docs doctrines (state vs event, trigger not data, keys are forever), the test matrix and the manual verification journey, and an explicit out-of-scope list.
> 
> \### Related request
> 
> Forum: \`\`https://community.gladysassistant.com/t/permettre-aux-integrations-externes-de-declarer-leur-propre-declencheur-actions-de-scenes\`\`/10870
> 
> \### Checklist
> 
> \- \[x\] If a forum topic or GitHub issue exists, the description links it (\`Forum: https://community.gladysassistant.com/t/...\` or \`Closes #...\`)
> \- \[\] Tests pass: \`cd server && npm run coverage\` (Codecov requires 100% coverage on changed lines) and Cypress (\`npm run cypress:run\`) if the UI changed — not applicable, documentation only
> \- \[\] Linter and prettier pass on both front and server (\`npm run eslint\`, \`npm run prettier\`) — not applicable, documentation only
> \- \[x\] No undocumented breaking change
> 
> 🤖 Generated with \[Claude Code\](https://claude.com/claude-code)
> 
> https://claude.ai/code/session\_01SzdCt7PkgNaicRRsFLnzkJ
> 
> \---
> \_Generated by \[Claude Code\](https://claude.ai/code/session\_01SzdCt7PkgNaicRRsFLnzkJ)\_

N’hésitez pas à suivre la PR, à tester (optionnel, surtout pour les petites demandes) et à faire vos retours ici si besoin.

---

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [Septembre 18, 2026, 12:29 UTC](https://community.gladysassistant.com/t/permettre-aux-integrations-externes-de-declarer-leur-propre-declencheur-actions-de-scenes/10870/3 "2026-09-18T12:29:16Z")

</div>

Salut à tous 👋

Le développement est prêt, et j’aurais besoin de quelques testeurs pour vérifier que ça répond bien au besoin avant la mise en production 😄

Voilà le rendu :

 ![13-install-page](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/d/9/d9604c054e3da0c4fd436a8f40a10bbcd3da58ed.jpeg)  
 ![09-full-scene-expanded](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/2/6/2685e0e9347f8679dfba322fe155b3d24117cf6d.jpeg)  
 ![06-action-card](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/4/9/49642e591a591c4182e46c3677a7eb39bb3c7d2d.jpeg)  
 ![04-trigger-card-filled](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/8/7/870c232d8a61b4f5fad6e9b7cb69eb7414fd5b22.jpeg)

La PR contenant la spec est ici :

> <https://github.com/GladysAssistant/Gladys/pull/3110>
>
> \### Description
> 
> Spec and implementation of scene triggers and scene actions dec…lared by external integrations, so Gladys can be extended without a core update. The spec is \`docs/specs/external-integrations/capabilities/scene-triggers-and-actions.md\` (a self-contained capability file of the living spec); the code follows it.
> 
> \> \*\*Stacked on #3109\*\* (dashboard widgets, \`provider\` type), which lands first: the base of this PR is its branch, so the diff shown here is only the scene work. GitHub retargets it to \`master\` once #3109 is merged. The widgets branch is merged in (\`38cf8d4\`): both capabilities sit side by side in the manifest validator, the vendored schema, the supervisor, the install screen and the i18n files, and \`scene\_triggers\` / \`scene\_actions\` join \`CAPABILITY\_MANIFEST\_FIELDS\`, so a \`provider\` integration whose whole contract is its scene declarations (an events-only bridge) is accepted, in code and in the schema (\`provider-type.md\` table updated).
> 
> \*\*Manifest\*\* (\`server/lib/external-integration/externalIntegration.validateManifest.js\`, vendored \`manifest.schema.json\`): two optional top-level fields, \`scene\_triggers\` and \`scene\_actions\` (1–20 each), declarable by every integration type (\`provider\` included). Triggers carry \`fields\` (filters, the \`config\_schema\` flat format with a restricted type list, no \`boolean\`) and \`variables\` (the whitelist of the event data exposed to the scene). Actions carry \`fields\` (\`boolean\` allowed), \`timeout\_seconds\` (5–120, default 30) and \`outputs\` (scalars only). \`secret\`/\`oauth2\`/\`account\_link\` and \`{{port:\<name\>}}\` are refused.
> 
> \*\*Scene engine\*\*: one generic trigger type \`external-integration.scene-event\` and one generic action type \`external-integration.scene-action\`, carrying \`integration\` (selector), \`trigger\_key\` / \`action\_key\` and a nested \`fields\` object validated by Joi for its shape only (the manifest is consulted at execution time, never at save time, so a scene loads and saves when its integration is gone). The matcher compares the stored filters with the event's \`filters\` (equality, \`multi\_select\` membership, empty = wildcard, stale keys skipped) and returns the reduced trigger event \`{ type, integration, trigger\_key, data }\`; \`checkTrigger\` now takes an object return as the \`triggerEvent\` (a boolean keeps the raw event, every existing checker is unchanged). The action handler resolves the proxy service through \`service.getService(selector)\`, relays the stored fields with a \`render\` callback bound to the scope, and writes the whitelisted outputs to the scope at the action path (replacing a previous run, never merging).
> 
> \*\*Supervisor\*\*: \`POST /api/integration/v1/scene/event\` \`{ key, data }\` builds \`filters\` (declared fields minus sections) and \`data\` (declared variables) with coercion by declared type, \`404\` on an undeclared key, \`400\` on nested data, 300 events/min on a counter separate from the states. \`runSceneAction\` reads the current \`t\_service\` row on every run (like \`runAction\`, so an update is live without a restart), strips stale keys and empty optionals, applies defaults, renders the declared \`string\` fields only, validates with the config engine (\`source: "devices"\` included), reserves an in-flight slot (10 per integration) before the connection wait, and relays \`external-integration.scene-action.run\` under a single deadline covering the wait and the ack. The proxy service carries \`scene.runAction\` on every external integration and is re-registered by \`update\`. \`GET /api/v1/external\_integration/scene\` (every authenticated user, literal route before \`:selector\`) feeds the editor. The MCP scene schemas accept the two types.
> 
> \*\*Frontend\*\*: a dynamic "Integrations" category in both type pickers (one entry per declaration, subtitled by the integration name), trigger and action cards rendered with the shared \`ConfigField\` engine (\`components/integration/ConfigSchemaForm\`, string action fields use the variables-aware input), declared variables and outputs exposed to the variable picker and named to the user by label only (one muted line of badges per card, no \`{{…}}\` path ever shown), a required filter left empty blocks the save with a message naming the field, the declaration catalog kept in three states (unknown / empty / loaded: a pending or failed request shows a loading line and refuses the save instead of posing as "nothing installed"), \`fields.\*\` string values rewritten on reorder, orphan (uninstalled / key removed) and stopped cards flagged honestly and never edited behind the user's back, one disclosure line on the install screen next to the widgets one. \`getLocalizedText\` moved to \`front/src/utils/\`. Strings in en/fr/de.
> 
> \*\*Tests\*\*: manifest (provider with scene declarations only included), host API (auth battery, whitelists, coercion, tenant isolation, rate limit), trigger matching (reduced scope, stale keys, wildcards, membership, strict equality), action handler, supervisor (order of the pipeline, slot reserved before the wait, single deadline, outputs, current declaration after an update), proxy capability, scene model, management API (route order, non-admin), MCP schemas, and a Cypress spec (\`front/cypress/e2e/routes/scene/SceneExternalIntegration.cy.js\`) run locally against a real server, together with the widget spec of #3109 on the merged front. The whole flow was also exercised end to end with a test integration process (manifest with two triggers and two actions, WebSocket + host API): event published → scene triggered → action relayed with rendered fields → outputs read by the following message action.
> 
> Not in this PR (other repositories): the indexer schema of \`integration-store\`, the SDK members \`publishSceneEvent\` / \`onSceneAction\`, the template demo declarations and the developer documentation page, as listed in §10 of the spec.
> 
> \### Related request
> 
> Forum: https://community.gladysassistant.com/t/10870
> 
> \### Checklist
> 
> \- \[x\] If a forum topic or GitHub issue exists, the description links it (\`Forum: https://community.gladysassistant.com/t/...\` or \`Closes #...\`)
> \- \[x\] Tests pass: \`cd server && npm run coverage\` (Codecov requires 100% coverage on changed lines) and Cypress (\`npm run cypress:run\`) if the UI changed
> \- \[x\] Linter and prettier pass on both front and server (\`npm run eslint\`, \`npm run prettier\`)
> \- \[x\] No undocumented breaking change
> 
> 🤖 Generated with \[Claude Code\](https://claude.com/claude-code)
> 
> https://claude.ai/code/session\_01SzdCt7PkgNaicRRsFLnzkJ

Vous pouvez tester avec cette image Docker :

```auto
ghcr.io/gladysassistant/gladys-preview:claude-wonderful-albattani-8v9pbw

```

Tous les retours sont les bienvenus ! Si tout est bon, je prévois de publier ça lundi 🚀

---

<div class="post-metadata">

**Author:** ![spenceur](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/spenceur/32/1961_2.png) [@spenceur](https://community.gladysassistant.com/u/spenceur)\
**Post date:** [Septembre 18, 2026, 12:58 UTC](https://community.gladysassistant.com/t/permettre-aux-integrations-externes-de-declarer-leur-propre-declencheur-actions-de-scenes/10870/4 "2026-09-18T12:58:25Z")

</div>

Je testerais ça aussi 👀

---

<div class="post-metadata">

**Author:** ![cicoub13](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/cicoub13/32/4482_2.png) [@cicoub13](https://community.gladysassistant.com/u/cicoub13)\
**Post date:** [Septembre 19, 2026, 12:31 UTC](https://community.gladysassistant.com/t/permettre-aux-integrations-externes-de-declarer-leur-propre-declencheur-actions-de-scenes/10870/5 "2026-09-19T12:31:10Z")

</div>

Testé avec [Intégration externe - Prochains passages de l'ISS](https://community.gladysassistant.com/t/integration-externe-prochains-passages-de-liss/10884) 🚀  
Aucun souci, ni lors du développement, ni lors des tests (le déclencheur récupère des valeurs utilisables en variables dans la suite de la scène)

 ![Capture d’écran 2026-09-19 à 14.22.50](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/c/a/ca54ab05f55d194a6a693f440283c8521dcab5de.png)  
 ![Capture d’écran 2026-09-19 à 14.23.04](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/d/6/d67afdee3a1ef165d7c5ce380b87c77321396a21.png)  
 ![Capture d’écran 2026-09-19 à 14.23.53](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/e/4/e4c240351888e9d590982f37789c416c1b951893.jpeg)

---

<div class="post-metadata">

**Author:** ![prohand](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/prohand/32/15713_2.png) [@prohand](https://community.gladysassistant.com/u/prohand)\
**Post date:** [Septembre 20, 2026, 7:15 UTC](https://community.gladysassistant.com/t/permettre-aux-integrations-externes-de-declarer-leur-propre-declencheur-actions-de-scenes/10870/6 "2026-09-20T19:15:31Z")

</div>

Testé sur «&nbsp;Prix carburants&nbsp;» c’est good 🙂 :

Déclencheurs :

 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/1/a/1a2e1d26dadf34a20758ce07b7b2c0c79d2bb308.png)  
 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/a/6/a6d80b3221dd3a5c9707e9e6674e451a13f5876b.png)

Actions :

 ![image](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/c/1/c1beba7950e95c077b7b6abf226b6730de5149f2.png)

---

<div class="post-metadata">

**Author:** ![pierre-gilles](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/pierre-gilles/32/5886_2.png) [@pierre-gilles](https://community.gladysassistant.com/u/pierre-gilles)\
**Post date:** [Septembre 21, 2026, 9:16 UTC](https://community.gladysassistant.com/t/permettre-aux-integrations-externes-de-declarer-leur-propre-declencheur-actions-de-scenes/10870/7 "2026-09-21T09:16:20Z")

</div>

Merci @prohand pour le test sur « Prix carburants », et merci @cicoub13 pour l’ISS 🙏

En regardant tes captures, j’ai vu un petit défaut d’affichage dans le sélecteur de déclencheurs et d’actions : avec des libellés longs, les titres des trois colonnes n’étaient pas à la même hauteur, et le nom de l’intégration se repliait au milieu du titre.

C’est corrigé dans la PR : les entrées sont maintenant alignées en haut, et le nom de l’intégration est sur sa propre ligne sous le titre 🙂

 ![picker-actions-after](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/2/a/2a2a22ebe0d07200cf738ec5c848ce7763f23aeb.png)  
 ![picker-triggers-after](https://gladys-assistant-community.b-cdn.net/uploads/default/original/3X/0/1/01e8f06562dc9ed3ff7307080dfd63f37b361492.png)

Ce sera dans la même release que la fonctionnalité !

---

<div class="post-metadata">

**Author:** ![cursor-bot](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/cursor-bot/32/22252_2.png) [@cursor-bot](https://community.gladysassistant.com/u/cursor-bot)\
**Post date:** [Septembre 21, 2026, 6:40 UTC](https://community.gladysassistant.com/t/permettre-aux-integrations-externes-de-declarer-leur-propre-declencheur-actions-de-scenes/10870/8 "2026-09-21T18:40:46Z")

</div>


