---
title: "Déclencheurs"
description: "Un déclencheur démarre une session selon un calendrier, à partir d’un webhook, d’un événement d’application ou d’un moniteur."
---

Un déclencheur démarre une [session](/docs/fr/work/sessions) sans présence humaine. Utilisez un déclencheur pour automatiser des tâches récurrentes ou déclenchées par un événement.

Pour reprendre plus tard la tâche d’une session — « vérifier demain si la personne a répondu » — utilisez plutôt un [rappel](/docs/fr/connect/reminders). Un rappel est un déclencheur associé à cette session. Il est stocké dans la base de données, pas dans `beeuni.yaml`.

<a id="trigger-types"></a>

## Types de déclencheurs

Beeuni prend en charge quatre types de déclencheurs.

- **cron** — s’exécute selon un calendrier que vous définissez.
- **webhook** — s’exécute lorsqu’un service externe envoie une requête signée à l’URL du webhook du projet.
- **event** — s’exécute lorsqu’un événement survient dans une application connectée, comme une nouvelle pull request ou un nouvel e-mail. Voir [Déclencheurs d’événements d’application](#app-event-triggers).
- **monitor** — exécute une commande de votre dépôt 24 h/24, 7 j/7. Chaque ligne que la commande écrit sur stdout déclenche le déclencheur. Fonctionnalité expérimentale : voir [Moniteurs](#monitors).

Vous définissez les déclencheurs dans le manifeste du projet, `beeuni.yaml`. Chaque déclencheur contient une invite qui devient le premier message de la session déclenchée. L’état d’exécution — comme l’heure de la dernière exécution et le statut — est stocké dans la base de données, hors du manifeste. Le déclenchement ne crée pas de commit.

Créer, modifier ou supprimer un déclencheur depuis le tableau de bord écrit directement dans la branche par défaut. Cela ne passe pas par une [demande de modification](/docs/fr/work/change-requests) (CR). Modifier `beeuni.yaml` dans une session et exécuter `beeuni ship` suit plutôt le processus habituel de branche et de CR.

<a id="set-up-a-cron-trigger"></a>

## Configurer un déclencheur cron

1. **Ajouter le déclencheur**

    ```sh
    beeuni triggers add daily-digest --type cron \
      --cron "0 0 9 * * 1-5" --timezone America/Los_Angeles \
      --prompt "Summarize yesterday's activity and save it as a daily note."
    ```

    `cron` est une expression à 6 champs : seconde, minute, heure, jour, mois, jour de la semaine. Un déclencheur se lance au plus une fois par minute : `0 */30 * * * *` correspond à toutes les 30 minutes, et `*/30 * * * * *` (toutes les 30 secondes) est refusé. Cette commande modifie uniquement votre `beeuni.yaml` local.

2. **Publier**

    ```sh
    beeuni ship
    ```

    `beeuni ship` valide `beeuni.yaml` et le pousse. Le calendrier est activé dès que cela arrive dans la branche par défaut de votre projet.

3. **Vérifier son exécution**

    ```sh
    beeuni triggers ls
    ```

    La liste affiche le slug et l’état de chaque déclencheur, ainsi que la date de son dernier déclenchement. Pour le déclencher maintenant plutôt que d’attendre le calendrier, exécutez `beeuni triggers fire daily-digest`. La commande attend le résultat de l’exécution et renvoie un code de sortie non nul avec le texte d’erreur en cas d’échec ; `--wait <dur>` limite la durée d’attente (valeur par défaut : `90s`).

<a id="set-up-a-webhook-trigger"></a>

## Configurer un déclencheur webhook

Un déclencheur webhook nécessite un secret. Beeuni l’utilise pour vérifier la signature de chaque requête entrante.

1. **Ajouter le secret**

    ```sh
    beeuni secrets set WEBHOOK_SECRET=<a-random-value>
    ```

    Voir [Secrets](/docs/fr/project/secrets) pour en savoir plus sur les secrets.

2. **Ajouter le déclencheur**

    ```sh
    beeuni triggers add new-lead --type webhook \
      --secret-env WEBHOOK_SECRET \
      --prompt "A new lead arrived: {{ body.name }} ({{ body.email }}). Add it to the CRM."
    ```

    `--secret-env` indique le secret utilisé pour signer les requêtes adressées à ce déclencheur.

3. **Publier**

    ```sh
    beeuni ship
    ```

4. <a id="send-it-a-request"></a>

    ### Envoyer une requête

    Beeuni construit l’URL du webhook à partir de l’identifiant de votre projet et du slug du déclencheur :

    ```
    POST /v1/webhooks/projects/<project-id>/<slug>
    ```

    Envoyez à cette URL, depuis le service externe, une requête `POST` signée. Beeuni vérifie la signature à l’aide de `WEBHOOK_SECRET`, puis démarre une session dont l’invite contient le corps de la requête. Consultez [Signature du webhook](#webhook-signature) ci-dessous pour connaître l’en-tête et le format exacts.
Par défaut, chaque déclenchement démarre une nouvelle session sur une nouvelle branche. Un déclencheur peut réutiliser ou épingler une session, et un déclencheur webhook peut filtrer les charges utiles qui démarrent une session — voir [Stratégie de session](#session-strategy) et [Modèles de charge utile](#payload-templating) ci-dessous.

<a id="app-event-triggers"></a>

## Déclencheurs d’événements d’application

Un déclencheur d’événement lance un agent lorsqu’un événement survient dans une application : une pull request est ouverte, un e-mail arrive, l’état d’une issue change. Vous n’avez pas à configurer de webhook, de secret ou de signature. Beeuni s’abonne à l’événement pour vous et s’occupe de la signature.

Un événement provient d’une **source d’événements** : un adaptateur qui transmet les événements d’une application. Les identifiants tels que `GITHUB_PULL_REQUEST_CREATED` désignent les événements pris en charge par cette source. Utilisez le catalogue d’événements pour choisir un événement pour votre connecteur.

<a id="set-up-in-the-web-app"></a>

### Configuration dans l’application Web

1. Ouvrez le projet, puis **Triggers** et **New trigger**.
2. Choisissez **App event**.
3. Choisissez une application. Sélectionnez ensuite un connecteur et l’un de ses comptes partagés, ou connectez un autre compte. Le compte marqué **Default** est utilisé, sauf si vous en choisissez un autre.
4. Choisissez un événement. Le formulaire de ses paramètres, comme le dépôt, s’affiche en dessous.
5. Rédigez l’invite et enregistrez.

Le déclencheur est actif dès que son badge indique **Live**. Les autres badges sont **Activating**, **Needs connection** et **Error**. Ils correspondent aux statuts `pending`, `needs_connection` et `error` ci-dessous.

<a id="see-every-app-event-trigger"></a>

### Afficher tous les déclencheurs d’événements d’application

Dans l’application Web, ouvrez **Triggers** et choisissez **App events**. La rangée de filtres affiche **All**, **Schedules**, **App events** et **Webhooks**, chacun avec un nombre. Le choix est conservé dans l’adresse sous la forme `?type=event`, ce qui permet de créer un lien vers cette page. Les lignes sont regroupées par application. En dessous, **Apps with events** répertorie toutes les applications pouvant lancer un agent, en affichant d’abord celles déjà utilisées par votre projet. Choisissez-en une pour ouvrir le formulaire de création d’un déclencheur associé à cette application.

La fenêtre d’un connecteur comporte un onglet **Triggers** qui affiche les événements d’application disponibles pour ce connecteur. Cet onglet apparaît uniquement pour les applications qui proposent des événements.

Avec la CLI :

```bash
beeuni triggers ls --type event                 # every app event trigger, grouped by app
beeuni triggers ls --connector github-work      # the app events on one connector
beeuni triggers ls --type event --json          # the same list as JSON
```

`--type` accepte également `cron`, `webhook` et `monitor`. `--connector` et `--type` peuvent être combinés.

<a id="set-up-with-the-cli"></a>

### Configuration avec la CLI

Un agent ou une personne exécute ces étapes dans l’ordre. Chaque étape affiche les informations nécessaires à la suivante.

```sh
beeuni triggers events --apps
beeuni triggers events --app github
beeuni connectors add github --provider composio --app github --apply
beeuni connectors connect github --owner project
beeuni triggers events --connector github
beeuni triggers events --connector github --event GITHUB_PULL_REQUEST_CREATED
beeuni triggers add pr-review --type event \
  --connector github --event GITHUB_PULL_REQUEST_CREATED \
  --config repo=hekmat/api \
  --prompt "Review {{ event.data.html_url }}" --apply
beeuni triggers info pr-review
```

1. `triggers events --apps` répertorie les applications pouvant déclencher des événements. Elles sont regroupées sous leur source d’événements (`source: composio`). Chaque application répertorie ses connecteurs (profils) et leurs comptes partagés. La colonne `STATE` affiche `connected` ou `needs account` ; les applications sans connecteur apparaissent sous `No connector yet`.
2. `connectors add` ajoute le connecteur si l’application n’en a pas. Ignorez cette étape si `CONNECTOR` est défini.
3. `connectors connect <slug> --owner project` affiche un lien. Une personne l’ouvre pour connecter le compte partagé. Le compte privé d’un membre n’est pas pris en compte. Exécutez à nouveau la commande pour ajouter un deuxième compte partagé, puis attribuez-lui un libellé avec `connectors rename <id> <label>`.
4. `triggers events --connector <slug>` répertorie les événements. Ajoutez `--event <TYPE>` pour afficher les paramètres d’un événement et ses variables `{{ event.data.* }}`. Lisez la description de chaque paramètre : certains événements attendent un nom complet dans un seul paramètre, comme `repo: hekmat/api`, et refusent la même valeur répartie entre `owner` et `repo`.
5. `triggers add --apply` crée le déclencheur immédiatement et affiche son statut ainsi que l’étape suivante. Si un paramètre est manquant ou invalide, la commande renvoie le code 2 et répertorie tous les problèmes. Sans `--apply`, la CLI écrit le bloc dans le `beeuni.yaml` local ; exécutez `beeuni ship` pour l’appliquer.
6. `triggers info <slug>` affiche le statut. Répétez jusqu’à ce qu’il indique `live`.

`--source <adapter>` définit la source d’événements et est facultatif : sans cette option, le déclencheur utilise le fournisseur du connecteur. Le connecteur doit appartenir à cette source. Une source `composio` sur un connecteur d’un autre fournisseur affiche `error` : `Connector "<slug>" is a <provider> connector; source "composio" needs a composio connector.` Une source inconnue est rejetée avec `Unknown event source "<x>". Sources: composio.`. `beeuni triggers set <slug> --source <adapter>` la modifie ; modifier `--connector` l’efface.

`--config key=value` se répète pour chaque paramètre et est converti au type de ce paramètre. `--config-json '{"limit": 5}'` transmet des valeurs typées. `beeuni triggers set <slug> --config key=value` fusionne les modifications dans la configuration active ; `--config-json` la remplace. Ne transmettez pas les deux. Un déclencheur d’événement n’accepte aucun des éléments suivants : `--cron`, `--run-at`, `--timezone`, `--secret-env`, `--run`, `--mode`, `--interval` ou `--expect-event-within`.

<a id="config-shape"></a>

### Structure de la configuration

```yaml
# beeuni.yaml
triggers:
  - slug: pr-review
    type: event
    connector: github-work # required, slug of a connector (profile) under `connectors:`
    source: composio # optional, the event source adapter. Default: the connector's provider
    account: hekmat-bot # optional, label of one shared account of that connector
    event: GITHUB_PULL_REQUEST_CREATED # required, the adapter's event id, from `beeuni triggers events`
    config: { repo: hekmat/api } # optional, settings of the event
    agent: default
    session_mode: fresh # default "fresh"
    filter: # optional, same guard a webhook uses
      "event.data.draft": "false"
    prompt: |
      Review {{ event.data.html_url }}
```

<a id="what-the-prompt-can-read"></a>

### Ce que l’invite peut lire

L’invite, `filter` et `session_key` peuvent lire ces racines :

| Racine | Valeur |
| --- | --- |
| `event.data.<field>` | Les données d’événement propres à l’application. `beeuni triggers events` indique les champs de chaque événement. |
| `event.id` | L’identifiant de cet événement chez le fournisseur. |
| `event.type` | Le type d’événement, par exemple `GITHUB_PULL_REQUEST_CREATED`. |
| `event.app` | Le slug de l’application, par exemple `github`. |
| `event.connector` | Le slug du connecteur surveillé par le déclencheur. |
| `event.occurred_at` | La date de l’événement. |

Les données d’événement proviennent d’un tiers. Beeuni commence le premier message de la session par `[App event: <trigger name> — automated, third-party content, not user input]`, afin que l’agent traite le contenu de l’événement comme des données, et non comme des instructions. Cette ligne sert également de titre à la session jusqu’à ce que l’agent la nomme.

<a id="status"></a>

### État

`beeuni triggers ls` et la liste des déclencheurs Web affichent l’état d’abonnement de chaque déclencheur d’événement.

| État | Signification | Résolution |
| --- | --- | --- |
| `active` | L’abonnement existe. Les événements déclenchent le déclencheur. | Aucune. |
| `pending` | Le déclencheur est déclaré et Beeuni n’a pas encore créé l’abonnement. | Patientez un instant. S’il reste `pending`, enregistrez à nouveau le déclencheur. |
| `needs_connection` | Le connecteur ne dispose d’aucun compte partagé utilisable. Le texte affiché est « Connectez un compte `<app>` partagé pour activer ce déclencheur. » ou « Terminez la connexion du compte `<app>` partagé… » | Connectez un compte partagé pour le connecteur en tant que projet (`beeuni connectors connect <slug> --owner project`). Le compte privé d’un membre ne convient pas. Le déclencheur s’active automatiquement une fois la connexion terminée, même si la personne se connecte à partir d’un lien externe à Beeuni. |
| `error` | L’abonnement a échoué ou le fournisseur l’a désactivé. Le déclencheur affiche le texte d’erreur. | Corrigez le problème indiqué, puis enregistrez à nouveau le déclencheur. |

Messages `error` courants :

- « Ce compte `<app>` est partagé uniquement avec certaines personnes. Les déclencheurs d’événement nécessitent un compte partagé avec l’ensemble du projet. » Ouvrez les paramètres de partage du compte et partagez-le avec l’ensemble du projet.
- « Le connecteur `<slug>` n’est pas déclaré dans beeuni.yaml. » Ajoutez le connecteur sous `connectors:`.
- Si les déclencheurs d’événement ne sont pas disponibles, contactez l’assistance.

- « L’application a désactivé cet abonnement : … » Le fournisseur a désactivé l’abonnement. Enregistrez à nouveau le déclencheur pour vous réabonner.
- « Le compte connecté a expiré : … » L’application a révoqué le compte ou celui-ci a expiré. Reconnectez l’application pour réactiver le déclencheur.

<a id="rules"></a>

### Règles

- **Connecteur et compte.** Une *application* est un service, tel que GitHub. Un *connecteur* est un profil dans `beeuni.yaml` ; plusieurs connecteurs peuvent utiliser la même application. Un *compte* est une connexion associée à un connecteur. Un déclencheur désigne un connecteur. Il utilise le compte partagé par défaut de ce connecteur, sauf s’il définit `account: <label>`. Définissez `account` uniquement si un connecteur possède plusieurs comptes partagés. Dans la CLI, `--account <label>` le définit et `--default-account` (sur `triggers set`) l’efface. Si aucun compte partagé ne correspond au libellé, l’état devient `needs_connection` avec le texte « Connectez un compte `<app>` partagé nommé “`<label>`” sur `<connector>`. »
- **Un seul compte source.** Seul un compte partagé avec l’ensemble du projet peut alimenter un déclencheur. Un déclencheur s’exécute sans personne présente, et les données d’événement sont intégrées à une invite de session. Un compte partagé uniquement avec des personnes nommées, ou un compte privé, ne peut jamais l’alimenter.
- **Chaque événement ne déclenche qu’une fois.** Un déclencheur se déclenche une fois par événement du fournisseur. La retransmission d’un événement ne démarre pas une deuxième session. Deux déclencheurs portant sur le même événement se déclenchent chacun une fois.
- **La pause arrête le déclenchement.** Un déclencheur ou un projet en pause ignore les événements. Les événements ignorés ne sont pas mis en file d’attente.
- **Les modifications réabonnent.** Modifier `connector`, `source`, `account`, `event` ou `config` remplace l’abonnement. Supprimer le déclencheur le supprime.

<a id="monitors"></a>

## Moniteurs

**Expérimental.** Les moniteurs ne s’exécutent que lorsque l’indicateur de fonctionnalité `monitors` est activé. Il est désactivé par défaut. Lorsqu’il est désactivé, la plateforme ne provisionne aucun environnement de moniteur et ne déclenche aucun événement de moniteur.

Un moniteur surveille un élément qui ne transmet pas de webhooks et ne se prête pas à une planification : un journal en direct, la profondeur d’une file d’attente, une page qui change, un prix. Beeuni exécute votre commande 24 h/24 et 7 j/7 dans l’environnement de moniteur du projet — une microVM persistante par projet, avec la même limite d’isolation et les mêmes secrets de projet que ceux d’un environnement sandbox de session. Le code déterministe surveille ; l’agent ne se réveille que lorsque la commande émet une ligne.

Quatre règles définissent le fonctionnement :

- **Les lignes sur stdout sont des événements. Rien d’autre ne l’est.** Stderr sert au diagnostic : visible dans les journaux du moniteur, il ne déclenche jamais rien.
- Chaque ligne déclenche exactement une fois le déclencheur, par le chemin déjà utilisé par un webhook : `filter` → modèle d’invite → `session_mode`.
- **Un moniteur ne peut pas échouer sans laisser de trace.** La fin du processus, l’épuisement du budget de redémarrage et une absence de sortie supérieure à `expect_event_within` déclenchent chacun un événement de cycle de vie généré par la plateforme dans le même flux.
- Par défaut, `session_mode` vaut `reuse` pour un moniteur, et non `fresh`. Un moniteur se déclenche régulièrement par conception, donc `fresh` créerait une session par événement.

1. **Ajouter le moniteur**

    ```sh
    beeuni triggers add checkout-errors --type monitor \
      --run "./monitors/checkout-errors.ts" \
      --mode poll --interval 60s --expect-event-within 24h \
      --prompt "Checkout monitor emitted: {{ line }}"
    ```

    `--mode poll` réexécute la commande toutes les `--interval` et s’attend à ce qu’elle se termine. `--mode stream` l’exécute une fois et la maintient en fonctionnement ; un flux n’accepte aucun `--interval`. Les deux formes produisent des lignes, impossibles à distinguer pour les étapes suivantes. Un moniteur rejette `cron`, `run_at`, `timezone` et `secret_env`.

2. **Déployer**

    ```sh
    beeuni ship
    ```

    La plateforme démarre l’environnement de moniteur dès que ces modifications sont intégrées à la branche par défaut.

3. **Vérifier qu’il fonctionne**

    ```sh
    beeuni triggers ls
    beeuni triggers info checkout-errors
    ```

    `ls` affiche le mode et l’intervalle d’un moniteur, là où un cron affiche sa planification. `info` affiche `run`, `mode`, `interval` et `expect_event_within`.

<a id="monitor-limits"></a>

### Limites des moniteurs

La plateforme applique toutes les limites ci-dessous.

| Limite | Valeur |
| --- | --- |
| Moniteurs par projet | 10 activés |
| Intervalle d’interrogation | 30 s minimum |
| `expect_event_within` | 5 min minimum |
| Débit d’événements par moniteur | 60/heure en continu, rafale de 30. En cas de dépassement, le moniteur est suspendu pendant 10 minutes ; après 3 suspensions en 24 heures, il est désactivé. |
| Longueur de ligne | 8 Kio, tronquée avec un marqueur `truncated: true` |
| Budget de redémarrage | 5 redémarrages / 10 minutes, puis un événement de cycle de vie `restart_budget_exhausted` et une période d’attente de 15 minutes |
| Conservation des événements | 30 jours |
| Budget mensuel de l’environnement | 75 $ par défaut. Au-delà, l’environnement s’arrête et un événement de cycle de vie `budget_exceeded` est déclenché. |

L’environnement de moniteur nécessite un fournisseur prenant en charge un environnement sandbox persistant. Si le fournisseur du projet ne peut pas en héberger un, l’indicateur `monitors` indique qu’il n’est pas disponible.

<a id="config-shape-1"></a>

## Structure de la configuration

```yaml
# beeuni.yaml
triggers:
  - slug: daily-digest # required, lowercase + dashes, unique per project
    name: Daily digest # optional, defaults to slug
    type: cron # "cron" | "webhook" | "event" | "monitor", required
    agent: beeuni # optional, defaults to "default"
    model: anthropic/claude-sonnet-4-5 # optional, resolves at fire time if unset
    enabled: true # optional, default true
    cron: "0 0 9 * * 1-5" # 6-field expression, mutually exclusive with run_at
    timezone: America/Los_Angeles # IANA name, default UTC
    session_mode: reuse # "fresh" | "reuse" | "pinned" | "keyed", default "fresh"
    filter: # optional, webhook payload guard
      "body.data.direction": "inbound"
    prompt: "Summarize {{ body.text }}" # required, template string
```

Un moniteur remplace les champs de planification par sa commande et sa forme :

```yaml
# beeuni.yaml
triggers:
  - slug: checkout-errors
    type: monitor
    run: ./monitors/checkout-errors.ts # required, repo-relative command
    mode: poll # "poll" | "stream", required
    interval: 60s # required on poll, invalid on stream
    expect_event_within: 24h # optional silence watchdog
    agent: oncall
    session_mode: reuse # the monitor default
    filter: # optional, same guard a webhook uses
      "line.severity": "error"
    prompt: "Checkout monitor emitted: {{ line }}"
```

Un déclencheur d’événement remplace les champs de planification par l’application et l’événement qu’il surveille. Voir [Déclencheurs d’événements d’application](#app-event-triggers).

L’ancien `beeuni.toml` utilise les mêmes champs dans un conteneur différent ; voir [ancien format TOML](/docs/fr/project/legacy-toml).

<a id="fields"></a>

## Champs

| Champ | Requis | Valeur par défaut | Remarques |
| --- | --- | --- | --- |
| `slug` | oui | — | `[a-z0-9][a-z0-9_-]{0,127}`, unique par projet. |
| `type` | oui | — | `cron`, `webhook` ou `monitor`. |
| `prompt` | oui | — | Chaîne de modèle. S’affiche comme premier message de la session. |
| `name` | non | `slug` | Libellé visible. |
| `agent` | non | `default_agent` | Doit désigner une clé dans `agents:`. Omettez ce paramètre pour utiliser `default_agent` ; n’écrivez pas la valeur littérale `default`. |
| `model` | non | résolu au déclenchement | Format filaire `provider/model`, par exemple `anthropic/claude-sonnet-4-5`. |
| `enabled` | non | `true` | Lorsque `false`, le planificateur et le récepteur du webhook ignorent l’entrée. |
| `session_mode` | non | `fresh` ou `reuse` pour un moniteur | Voir [Stratégie de session](#session-strategy). |
| `session_id` | requis pour `pinned` | — | Session exacte à relancer. |
| `session_key` | requis pour `keyed` | — | Chaîne de modèle. La définir seule implique `session_mode: keyed`. |
| `filter` | non | — | Chemin à points → chaîne attendue. Une livraison de webhook qui ne correspond pas renvoie `200` et ne déclenche aucune session. |
| `cron` | soit `cron`/`run_at`, sur `type: cron` | — | Expression à 6 champs : seconde, minute, heure, jour, mois, jour de la semaine. Se déclenche au plus une fois toutes les 60 secondes ; une expression plus rapide échoue `beeuni validate` et l’API. |
| `run_at` | soit `cron`/`run_at`, sur `type: cron` | — | Horodatage ISO-8601. Se déclenche une fois, puis reste en veille. |
| `timezone` | non, cron uniquement | `UTC` | Nom IANA. |
| `secret_env` | requis, webhook uniquement | — | Nom d’un secret de projet contenant la clé de signature. Le secret doit utiliser la livraison `broker` avec le consommateur `connector`. |
| `run` | requis, moniteur uniquement | — | Commande relative au dépôt dont les lignes de sortie standard constituent les événements. Une ligne, 1024 caractères maximum. |
| `mode` | requis, moniteur uniquement | — | `poll` relance `run` toutes les `interval` ; `stream` l’exécute une fois et le laisse actif. |
| `interval` | requis pour `mode: poll` | — | Littéral de durée (`30s`, `5m`, `24h`, `7d`), minimum `30s`. Non valide sur `mode: stream`. |
| `expect_event_within` | non, moniteur uniquement | — | Littéral de durée, minimum `5m`. Une absence d’activité supérieure à cette durée déclenche un événement de cycle de vie. |

Un déclencheur cron nécessite `cron` ou `run_at`, jamais les deux. Un déclencheur webhook sans `secret_env` est rejeté — les webhooks non authentifiés n’existent pas. Un moniteur nécessite `run` et `mode`, et rejette directement `cron`, `run_at`, `timezone` et `secret_env` — un manifeste qui annonce une planification que le moteur de moniteur ne lit jamais serait mensonger.

Configurez le secret de signature avant de créer ou de mettre à jour un déclencheur webhook :

```bash
beeuni secrets set WEBHOOK_SECRET=-
beeuni secrets delivery WEBHOOK_SECRET broker --consumer connector
```

Transmettez la valeur à la première commande via l’entrée standard. Si le secret
utilisait auparavant la livraison sandbox, faites-le tourner après avoir modifié
le mode de livraison, car un sandbox existant peut conserver l’ancienne valeur.

<a id="session-strategy"></a>

## Stratégie de session

`session_mode` détermine quelle session est relancée lors d’un déclenchement. Beeuni essaie les modes ci-dessous dans l’ordre et passe au suivant si une étape échoue.

1. **`pinned`** — relance la session `session_id` exacte. Si cette session a disparu ou a échoué, passe au mode suivant.
2. **`keyed`** — applique `session_key` à la charge utile, puis recherche la session non échouée la plus récente précédemment associée à cette clé exacte. Si la clé obtenue est vide ou qu’aucune session ne correspond, passe à une nouvelle session. Ne passe jamais à la session associée à une autre clé.
3. **`reuse`** — relance la session non échouée la plus récente créée auparavant par ce déclencheur. Un déclencheur épinglé revient aussi à ce mode avant de passer au suivant.
4. **`fresh`** — crée un nouveau sandbox et une nouvelle branche. Il s’agit du mode par défaut et du dernier recours pour tous les modes. La nouvelle session devient celle du déclencheur pour les prochains déclenchements `reuse` et `keyed`.

Une session `reuse` ou `keyed` dont l’historique ne tient plus dans le modèle, même après la compaction automatique, est retirée. Le déclenchement suivant démarre une nouvelle session. Toute autre erreur conserve la session pour le prochain déclenchement.

Un déclencheur cron fréquent qui ne doit pas renvoyer un historique sans cesse plus long peut renouveler sa session à la limite d’une période calendaire : `session_key: "merge-{{ cron.scheduled_date }}"` conserve une session sérialisée par jour UTC, et `{{ cron.scheduled_hour }}` une par heure UTC.

<a id="failed-runs"></a>

## Exécutions échouées

Lorsqu’une exécution lancée par un déclencheur se termine par une erreur, Beeuni l’enregistre sur le déclencheur :

- `last_status` devient `failed` et `last_error` contient la cause, par exemple `Out of credits: Payment Required: Insufficient credits.`
- La page Schedule indique « La dernière exécution ne s’est pas terminée » et affiche la cause dans son panneau.
- Le propriétaire du compte reçoit une notification push mobile lors du premier échec. Un échec ultérieur met à jour la cause sans envoyer d’autre notification.
- Le déclencheur reste `failed` tant qu’il continue de se déclencher. Un nouveau déclenchement ne prouve pas que son exécution fonctionne.

La prochaine exécution qui se termine efface l’échec. Une exécution que vous arrêtez vous-même, un sous-agent et un appel de modèle réessayé ne constituent pas des résultats d’exécution. Un déclenchement qui échoue avant le démarrage d’une exécution, par exemple parce qu’une session ne peut pas être créée, est effacé lors du prochain déclenchement réussi.

<a id="session-access"></a>

## Accès aux sessions

Par défaut, les sessions créées par un déclencheur utilisent la politique privée. Elles appartiennent au compte de service de l’agent du déclencheur — l’identité d’un agent est un principal `service_account`, qui peut donc posséder une session et détenir des affectations comme tout autre principal. Un gestionnaire de projet peut toujours les ouvrir. Le propriétaire et un administrateur du compte disposent d’un accès équivalent à celui d’un gestionnaire sur chaque projet ; la même règle s’applique donc à eux. La personne qui a configuré le déclencheur ou l’a lancé manuellement n’obtient pas d’accès par cette action, sauf si elle détient l’un de ces rôles.

Les paramètres du déclencheur proposent trois politiques :

- **Agent du déclencheur et gestionnaires de projet** — aucun membre ordinaire du projet ne peut ouvrir la session.
- **Coéquipiers sélectionnés** — l’agent du déclencheur, les gestionnaires de projet et les membres du projet ou groupes de comptes sélectionnés.
- **Projet entier** — tous les membres du projet.

Cette politique est un paramètre de visibilité par ressource qui s’ajoute au modèle de rôles ; ce n’est pas un rôle. Elle détermine qui peut ouvrir les sessions d’un déclencheur donné. Elle n’accorde aucune autorisation refusée par la décision relative au rôle. Voir
[Comptes et accès](/docs/fr/accounts#per-feature-access-settings).

La politique d’accès est un état d’exécution local au compte. Elle ne figure pas dans le manifeste `beeuni.yaml` portable, car les identifiants des principaux sont propres à chaque compte. Utilisez le tableau de bord pour la configurer.
La mise à jour de cette politique seule ne crée aucun commit Git. L’enregistrement d’une politique met également à jour les sessions antérieures créées par ce déclencheur.

Une session épinglée conserve ses propres paramètres de partage, car elle n’a pas été créée par le déclencheur. Si une session épinglée est indisponible et que le déclencheur crée une session de secours, la politique du déclencheur s’applique à cette nouvelle session.

<a id="payload-templating"></a>

## Modélisation des charges utiles

`prompt` et `session_key` sont rendus avec le même moteur : `{{ token.dotted.path }}`. Une valeur manquante donne une chaîne vide — aucune erreur ni `{{ }}` résiduel. Les objets et les tableaux sont rendus au format JSON. `session_key` est supprimé des espaces superflus et tronqué à 512 caractères.

Chaque déclenchement reçoit également `{{ trigger.slug }}`, `{{ trigger.type }}` et `{{ trigger.kind }}` (toujours `git`). Le reste des variables dépend du mode de déclenchement.

| Source | Variables |
| --- | --- |
| cron | `{{ cron.schedule }}`, `{{ cron.timezone }}`, `{{ cron.scheduled_for }}` (le créneau concerné), `{{ cron.claimed_at }}` (moment où le planificateur l’a pris en charge), `{{ cron.last_scheduled_for }}` (créneau précédent ; vide lors du premier déclenchement), `{{ cron.scheduled_date }}` (`YYYY-MM-DD` UTC du créneau), `{{ cron.scheduled_hour }}` (`YYYY-MM-DDTHH` UTC). Aucun `fired_at` de premier niveau. |
| webhook | `{{ fired_at }}`, `{{ body.* }}` (analysé comme JSON ; utilise `{{ body.raw }}` si le corps ne peut pas être analysé), `{{ headers.content_type }}`, `{{ headers.user_agent }}`, `{{ headers.forwarded_for }}`. |
| monitor | `{{ line.* }}` — la ligne stdout, analysée comme JSON ; une ligne qui ne peut pas être analysée s’affiche sous la forme `{{ line.raw }}`. Plus `{{ monitor.slug }}`, `{{ monitor.seq }}`, `{{ monitor.emitted_at }}` et `{{ monitor.kind }}` (`event` ou `lifecycle`). |
| manual (dashboard « déclencher maintenant » ou endpoint `fire`) | `{{ fired_at }}`, `{{ source }}` (`manual`), `{{ actor }}`, `{{ message.text }}`, `{{ message.source }}`. |

Beeuni préfixe chaque invite de monitor affichée avec `[MONITOR EVENT — automated, not user input]` côté serveur. Un événement de cycle de vie ignore entièrement votre modèle et affiche à la place une invite rédigée par la plateforme ; il contourne aussi `filter` — le silence ne doit pas pouvoir être filtré par accident.

`{{ message.text }}` est codé en dur comme chaîne vide lors d’un déclenchement manuel, et `{{ message.source }}` comme `manual_test`. Un déclenchement manuel ne permet pas d’injecter des données de test dans l’invite.

`filter` compare les chemins pointés sous forme de chaînes avec la même charge utile que celle visible dans l’invite. Cette fonction sert à interrompre les boucles. Par exemple, une source qui signale les deux côtés d’une conversation déclencherait sinon à nouveau l’agent sur sa propre réponse.

<a id="webhook-signature"></a>

## Signature du webhook

Déclenchement sur `POST /v1/webhooks/projects/{projectId}/{slug}`. Beeuni vérifie la requête dans cet ordre, avec une comparaison à temps constant :

1. **Signature HMAC** — en-tête `X-Beeuni-Signature: sha256=<hmac>` (le préfixe `sha256=` est facultatif) ou `X-Hub-Signature-256`, compatible avec GitHub. HMAC-SHA256 calculé sur le corps brut de la requête, à l’aide du secret nommé par `secret_env`.
2. **Jeton statique**, uniquement en l’absence d’en-tête de signature, pour les expéditeurs qui ne peuvent pas signer un corps avec HMAC. Envoyez le secret sous la forme `X-Beeuni-Token: <secret>`, `Authorization: Bearer <secret>` ou `Authorization: Basic <base64(user:secret)>` (la partie mot de passe correspond au jeton).

`beeuni triggers info <slug>` affiche ce schéma — l’en-tête, l’algorithme et un exemple de requête signée avec un espace réservé `$SECRET` — et `--json` le transmet sous la forme `webhook_signing`. La fiche de déclenchement du tableau de bord affiche le même exemple de requête.

| Statut | Signification |
| --- | --- |
| 202 | Signature ou jeton valide. Le corps est `{ status: "fired" \| "queued" \| "deduped", session_id, ... }`. |
| 200 | Valide, mais ignoré — le projet est en pause ou la livraison ne correspond pas à `filter`. |
| 400 | ID ou slug de projet mal formé dans l’URL. |
| 401 | Signature et jeton absents ou incorrects. |
| 404 | Déclencheur introuvable, désactivé, non-webhook ou projet inactif. |
| 409 | Le secret de signature est manquant, inactif, indisponible ou n’autorise pas le consommateur `connector`. La réponse inclut un code `webhook_secret_*` et des instructions pour résoudre le problème. |
| 500 | Authentification réussie, mais échec du déclenchement de la session. |

## Endpoints

| Méthode + chemin | Autorisation requise | Remarques |
| --- | --- | --- |
| `GET /v1/projects/{projectId}/triggers` | `project.trigger.read` | Répertorie les déclencheurs, l’état d’exécution (`last_fired_at`, `last_status`, `last_error`, `last_attempt_at`) et les erreurs d’analyse du manifeste. Une entrée incorrecte apparaît dans `errors[]` ; elle n’affecte pas les autres déclencheurs. |
| `POST /v1/projects/{projectId}/triggers` | `project.trigger.create` | Crée un déclencheur. Modifie directement le manifeste. |
| `PATCH /v1/projects/{projectId}/triggers/{slug}` | `project.trigger.update` | Mise à jour partielle, fusionnée avec l’entrée actuelle. |
| `DELETE /v1/projects/{projectId}/triggers/{slug}` | `project.trigger.delete` | Efface également l’état d’exécution du déclencheur. |
| `PATCH /v1/projects/{projectId}/triggers/activation` | `project.trigger.update` | Corps `{ paused: boolean }`. Voir [Mettre en pause et reprendre](#pause-and-resume). |
| `POST /v1/projects/{projectId}/triggers/{slug}/fire` | `project.trigger.fire` | Déclenchement manuel. Le rôle intégré `member` du projet détient `project.trigger.fire`, ce qui permet à un membre ordinaire de déclencher un déclencheur. |
| `POST /v1/webhooks/projects/{projectId}/{slug}` | signature ou jeton | URL publique, protégée par le secret du webhook. |

<a id="pause-and-resume"></a>

## Mettre en pause et reprendre

Un commutateur au niveau du projet arrête tous ses déclencheurs à la fois, indépendamment du champ `enabled` de chaque déclencheur. Pendant la pause, le planificateur ignore le projet et les webhooks entrants renvoient `200` avec `{ status: "skipped" }` — aucune session n’est déclenchée. Le déclenchement manuel reste possible. Utilisez cette option lorsque le même dépôt s’exécute sur deux plans de contrôle (par exemple, développement et production), afin d’éviter un double déclenchement de cron. CLI : `beeuni triggers pause` et `beeuni triggers resume`. Consultez [CLI](/docs/fr/cli) pour découvrir le groupe de commandes `beeuni triggers` complet.

<a id="limits-and-reliability"></a>

## Limites et fiabilité

- Le planificateur interroge le système environ chaque seconde (1 000 ms par défaut ; configurable via `BEEUNI_TRIGGER_SCHEDULER_INTERVAL_MS`). Une exécution cron ne démarre pas exactement à son créneau : chaque déclencheur reçoit un décalage fixe pouvant atteindre un quart de sa période, avec un maximum de 30 minutes, afin que de nombreux déclencheurs prévus à la même minute ne démarrent pas tous en même temps. La page de détail du déclencheur et `GET /triggers` (`next_fire_at`) indiquent l’heure de démarrage de la prochaine exécution.
- Un déclenchement qui échoue définit le dernier statut du déclencheur comme ayant échoué, avec l’erreur. Cela vaut pour toutes les sources : cron, manuel, webhook, événement d’application et monitor. Le prochain déclenchement réussi efface l’échec. Un échec d’exécution est effacé comme décrit dans [Échecs d’exécution](#failed-runs).
- Par défaut, chaque projet autorise le provisionnement simultané de 3 sessions déclenchées. Un déclenchement qui dépasse cette limite renvoie `queued` (`202`) au lieu d’échouer, et s’exécute dès que l’une des sessions a terminé son provisionnement. Le nombre de sessions exécutées simultanément n’est pas limité.
- Les déclenchements manuels ou par webhook expirent au bout de 45 secondes. Le chargement du manifeste expire au bout de 30 secondes.
- Un déclenchement cron est associé au créneau d’échéance prévu ; ainsi, un déclenchement qui a expiré mais a effectivement abouti ne sera pas dupliqué lors d’une nouvelle tentative.
- Chaque livraison de webhook s’exécute une fois par événement. Beeuni lit l’ID d’événement à partir de `X-Beeuni-Delivery-Id`, `X-GitHub-Delivery`, `X-Gitlab-Event-UUID`, `Linear-Delivery`, `webhook-id` ou `svix-id`, dans cet ordre ; une nouvelle tentative avec le même ID renvoie `202 { status: "deduped" }` et n’exécute rien. `X-Request-Id` n’est pas un ID d’événement. En l’absence d’ID d’événement, un corps et une signature identiques reçus dans un délai de 10 minutes sont considérés comme le même événement ; au-delà, l’exécution est relancée. Ainsi, une tâche qui envoie le même corps statique à chaque déploiement s’exécute à chaque déploiement. Envoyez `X-Beeuni-Delivery-Id` avec une nouvelle valeur pour chaque événement (l’exemple de requête utilise `$(uuidgen)`).
- Une livraison dont une tentative précédente a définitivement échoué (par exemple, parce que le compte n’avait plus de crédits), ou dont la session a été supprimée, est relancée lors d’une nouvelle livraison avec le même ID. Un doublon ne modifie pas `last_fired_at`.
