Webhooks Hermes : agents pilotés par événements sans méga-prompt fourre-tout
Intermédiaire7 min de lectureAutomations

Webhooks Hermes : agents pilotés par événements sans méga-prompt fourre-tout

Configurez les webhooks de Hermes Agent avec une authentification adaptée au fournisseur, des contrôles de santé sur le port 8644 et de petites routes nommées, afin que les événements deviennent des exécutions ciblées avec une cible de diffusion explicite.

Ce que vous saurez faire

Les webhooks sont préférables à cron lorsque quelque chose vient de se produire. Protégez chaque route Hermes avec la méthode d’authentification exigée par sa source, vérifiez /health sur le port 8644 et donnez à chaque type d’événement un prompt étroit avec une cible de diffusion configurée.

Enregistré uniquement dans ce navigateur.
Dans cet article

Cron demande « est-ce le moment ? » Les webhooks disent « cela vient de se produire, il faut agir ». Pour le travail d’un agent, cette distinction compte. Une consultation planifiée de la boîte de réception diffère de « un litige Stripe a été créé » ou « une pull request a été ouverte sur main ».

Les webhooks de Hermes Agent transforment des événements HTTP POST authentifiés en exécutions d’agent dont les résultats sont envoyés vers une cible de diffusion configurée. Bien utilisés, ce sont de petites portes verrouillées, chacune avec une tâche claire. Mal utilisés, ils deviennent un port exposé avec un méga-prompt qui essaie de traiter chaque bloc JSON envoyé par Internet.

Cet article couvre la conception de routes, l’authentification adaptée au fournisseur, le contrôle de santé documenté et un test de fonctionnement pratique. Associez-le au durcissement de la première semaine dans /articles/hermes-first-week-memory-and-skills avant d’exposer quoi que ce soit au-delà de localhost.

Quand les webhooks sont le bon déclencheur

Préférez les webhooks lorsque :

  • La latence compte (examiner une PR pendant que l’auteur en a encore le contexte en tête).
  • Le système source émet déjà des événements (GitHub, GitLab, Jira, Stripe, formulaires internes).
  • Chaque événement doit devenir une tâche ciblée, et non une longue session conversationnelle.

Préférez cron lorsque :

  • Vous recherchez périodiquement une dérive (« un certificat expire-t-il dans 14 jours ? »).
  • La source ne peut pas pousser d’événement.
  • Vous voulez un compte rendu périodique calme plutôt qu’une interruption pour chaque événement.

La recommandation officielle de Hermes suit cette distinction : cron pour les contrôles planifiés et les webhooks pour les exécutions déclenchées par un événement.

Architecture en une image

Système source (GitHub / GitLab / n8n / application personnalisée)
        |  HTTPS POST + authentification adaptée à la source
        v
Adaptateur webhook Hermes  (port par défaut 8644)
        |  route : /webhooks/<name>
        v
Configuration de route nommée (filtres + prompt + diffusion)
        v
Exécution de l’agent (skills/outils selon votre politique d’approbation)
        v
Diffusion configurée (canal de discussion, commentaire GitHub ou journal)

n8n peut se placer à gauche comme couche de validation et de regroupement : valider les champs, éliminer les données inutiles, puis envoyer à Hermes une charge utile minimale par POST. Il s’agit d’une architecture illustrative présentée dans /articles/hermes-vs-n8n-choose-by-job, et non d’une intégration fournisseur clé en main documentée. Si n8n doit récupérer le résultat de l’agent dans son flux de travail, appelez le serveur API Hermes distinct sur le port 8642 par défaut avec une authentification bearer, au lieu de traiter l’adaptateur webhook comme un callback synchrone.

Parcours de configuration (à vérifier dans la documentation actuelle)

La documentation sur les webhooks en amont décrit ce parcours :

  1. Activez la plateforme webhook (hermes gateway setup ou une variable d’environnement comme WEBHOOK_ENABLED=true).
  2. Configurez un secret pour chaque route. Utilisez l’en-tête HMAC de GitHub, l’en-tête de jeton en clair de GitLab ou le HMAC générique V2 horodaté, selon la source.
  3. Créez une route nommée dans la configuration ou avec hermes webhook subscribe (commande à confirmer dans la documentation actuelle).
  4. Contrôle de santé : curl http://localhost:8644/health
  5. Dirigez le système externe vers https://your-host/webhooks/<name>
  6. Envoyez une charge utile de test authentifiée ; confirmez la route, le prompt, le périmètre des outils et la cible de diffusion attendus.

Le port documenté par défaut est 8644. Les valeurs par défaut documentées limitent également une route à 30 requêtes par minute et rejettent les corps de plus de 1 Mo. Si vous les avez modifiées, testez les limites configurées au lieu de vous fier aux valeurs par défaut.

Les changements de configuration statique peuvent exiger le cycle de vie de la passerelle documenté par la version installée. Les routes dynamiques créées avec hermes webhook subscribe sont rechargées à chaud sans redémarrage et reçoivent un secret généré automatiquement. Dans les deux cas, confirmez que le processus de passerelle voit bien le profil et l’environnement prévus ; une commande qui réussit dans un shell interactif ne prouve pas que le démon dispose de la même configuration.

L’authentification des routes n’est pas facultative

Chaque route doit hériter d’un secret ou en définir un ; sinon, l’adaptateur échoue au démarrage. L’authentification dépend du fournisseur : GitHub utilise X-Hub-Signature-256, GitLab compare exactement X-Gitlab-Token, et les émetteurs personnalisés génériques doivent employer le HMAC V2 horodaté. Authentifier l’émetteur prouve quel détenteur du secret a envoyé la requête ; cela ne rend pas fiables les instructions contenues dans la charge utile.

Règles qui résistent en production :

  • Générez un long secret aléatoire ; stockez-le dans un gestionnaire de secrets ou un fichier d’environnement aux permissions verrouillées, jamais dans le Markdown d’un skill que l’agent pourrait lire par mégarde.
  • Préférez des secrets par route lorsque les systèmes ont des niveaux de confiance différents (application GitHub, formulaire interne, webhook partenaire).
  • Rejetez les signatures absentes ou invalides à la périphérie ; ne vous contentez pas de « journaliser et continuer ».
  • Utilisez INSECURE_NO_AUTH uniquement pour des tests temporaires sur l’interface de bouclage. L’adaptateur refuse de démarrer si cette valeur est associée à une liaison autre que le bouclage, comme 0.0.0.0 ou une adresse LAN.

Pour les émetteurs personnalisés, utilisez le schéma générique V2 actuel de Hermes : X-Webhook-Timestamp contient des secondes Unix ; X-Webhook-Signature-V2 est l’empreinte HMAC-SHA256 en hexadécimal minuscule de <timestamp>.<raw-body>. Hermes rejette les horodatages en dehors d’une fenêtre de ±300 secondes. V1 ne signe que le corps et n’offre aucune protection contre le rejeu ; ne construisez donc pas de nouvel émetteur dessus (contrat officiel de sécurité des webhooks).

Test de fonctionnement signé et reproductible

Après avoir créé une route nommée support-triage, placez une charge utile non sensible dans payload.json. Faites en sorte que votre mécanisme approuvé d’injection de secrets définisse WEBHOOK_SECRET avant le démarrage de ce shell ; ne saisissez pas un secret de production dans l’historique des commandes. La commande Node ci-dessous lit la clé depuis l’environnement au lieu de l’insérer dans les arguments du processus, et signe exactement les octets du fichier :

: "${WEBHOOK_SECRET:?inject a disposable route secret before running this test}"
timestamp="$(date +%s)"
signature="$(TIMESTAMP="$timestamp" node -e '
  const { createHmac } = require("node:crypto");
  const { readFileSync } = require("node:fs");
  const hmac = createHmac("sha256", process.env.WEBHOOK_SECRET);
  hmac.update(`${process.env.TIMESTAMP}.`, "utf8");
  hmac.update(readFileSync("payload.json"));
  process.stdout.write(hmac.digest("hex"));
')"

curl --fail-with-body \
  -H 'Content-Type: application/json' \
  -H "X-Webhook-Timestamp: $timestamp" \
  -H "X-Webhook-Signature-V2: $signature" \
  --data-binary @payload.json \
  http://127.0.0.1:8644/webhooks/support-triage

Recommencez ensuite sans aucun des deux en-têtes de signature, puis avec un horodatage antérieur de plus de 300 secondes. Les deux requêtes doivent être rejetées. Ne collez jamais un vrai secret dans des captures d’écran, des tickets ou l’historique du shell ; utilisez un secret de route jetable pour les tests de documentation, puis renouvelez-le.

Un webhook exposé qui peut placer du texte contrôlé par un attaquant devant un agent capable d’utiliser le terminal crée un risque d’exécution d’outils à distance. L’authentification limite les personnes qui peuvent soumettre des événements, mais le texte d’une charge utile authentifiée peut rester hostile. Utilisez TLS et des contrôles réseau, réduisez les charges utiles, limitez ou désactivez les outils de terminal, de fichiers et d’actions sortantes, puis isolez l’exécution de l’hôte. Les demandes d’approbation protègent l’intention de l’opérateur ; elles ne constituent pas un bac à sable contre les entrées hostiles.

Que mettre dans la charge utile

Envoyez à l’agent un contrat, pas un flux brut :

{
  "event_type": "github.pull_request.opened",
  "repo": "acme/api",
  "pr_number": 1842,
  "title": "Add billing retry worker",
  "author": "ada",
  "base_ref": "main",
  "html_url": "https://github.example.invalid/acme/agent-service/pull/1842",
  "task": "Summarize risk for main. List missing tests. Do not approve or merge."
}

Supprimez les champs inutilisés. Les exportations volumineuses de flux de travail gaspillent le contexte et favorisent un usage confus des outils. « Des charges utiles petites et explicites avec une tâche claire » est la recommandation de conception de cet article, et non une affirmation sur une intégration n8n officielle.

Conception des routes : beaucoup de petites portes

Ne construisez pas /webhooks/everything. Créez des routes nommées avec des filtres et des prompts :

Nom de routeSourceTâcheDiffusion
gh-pr-openedPR GitHub ouverteRésumé des risques + tests manquantsSujet Telegram de l’équipe d’ingénierie
stripe-disputeLitige Stripe crééBrouillon de liste de vérificationSlack de l’équipe finance + journal
support-formn8n après validationClasser + rédiger une réponseCanal Slack privé configuré
uptime-alertWebhook de supervisionRassembler le contexte des déploiements récentsCanal d’astreinte

Chaque route doit répondre à ces questions :

  1. Quels événements sont acceptés ?
  2. Quelle est la sortie unique attendue ?
  3. Quels outils sont autorisés pour le profil d’agent de cette route ?
  4. Où va le résultat ?
  5. Que se passe-t-il en cas d’échec (nouvelle tentative ? file de rejet ? alerter une personne ?) ?

Les charges utiles de webhook contiennent souvent des e-mails, des ID de compte ou des corps de message. Réduisez les champs avant qu’ils n’atteignent Hermes. Le schéma de route ne documente pas d’interrupteur d’écriture en mémoire propre à chaque route. Utilisez un profil dédié avec la mémoire désactivée ou memory.write_approval activé, puis testez ce qui persiste. Si aucun raisonnement d’agent n’est nécessaire, utilisez le mode deliver_only documenté au lieu d’exécuter un agent.

Contrôles de santé et opérabilité

Point de terminaison de santé documenté : http://localhost:8644/health (ou votre hôte/port). Utilisez-le pour :

  • Les tests de fonctionnement locaux après activation
  • Les sondes de disponibilité Docker/Kubernetes
  • Les contrôles de disponibilité externes sur une URL de santé privée, et non sur une route webhook non authentifiée

Journalisez également :

  • Les échecs de signature (attaque possible ou secret mal configuré)
  • Les échecs de validation de la charge utile
  • La durée d’exécution de l’agent et les refus d’approbation d’outils
  • Les échecs de diffusion en aval (API de discussion indisponible, etc.)

Sans ces signaux, « l’agent semblait capricieux » est votre seul rapport d’incident. Ces journaux améliorent l’observabilité ; ils ne constituent pas automatiquement une piste d’audit complète et inviolable.

Exemple : PR GitHub ouverte → exécution ciblée

Objectif : lorsqu’une PR s’ouvre sur main, Hermes rédige une note de risque à l’intention des humains. Il ne fusionne pas, n’approuve pas et ne commente pas tant que vous n’avez pas ajouté un parcours de diffusion vérifié.

  1. Créez la route gh-pr-opened. Pour une livraison directe depuis GitHub, configurez le secret partagé utilisé pour vérifier X-Hub-Signature-256 ; pour un relais n8n générique, implémentez plutôt le contrat HMAC V2 horodaté.
  2. Filtrez sur pull_request / opened / base main.
  3. Contrat du prompt : résumer le but, le périmètre des effets, les tests manquants et le risque de déploiement ; marquer les inconnues ; ne donner aucune instruction de fusion.
  4. Outils : récupération GitHub en lecture seule si elle est configurée ; shell désactivé ou soumis à approbation.
  5. Diffusion : publier le Markdown dans un canal interne ; une personne décide de la suite.

Exemple de structure d’une bonne sortie d’agent (structure illustrative ; la formulation du modèle variera) :

PR #1842 : Ajouter un worker de reprise de facturation (ada vers main)

Faits
- Modifie le worker de facturation et la configuration de la file (d’après le titre et la liste de fichiers fournis).
- URL associée : `https://github.example.invalid/acme/agent-service/pull/1842` (exemple)

Risques
- Tempête de nouvelles tentatives en l’absence de temporisation [inference; verify in diff]
- Aucune clé d’idempotence n’est mentionnée dans le titre [unclear]

Tests manquants à confirmer
- Comportement en cas de livraison en double ou de message poison
- Alerte lorsque le budget de nouvelles tentatives est épuisé

Ne fusionnez rien à partir de cette note. Une vérification humaine est requise.

Il s’agit d’une exécution d’agent pilotée par événement avec une règle d’arrêt. Ce n’est pas un propriétaire de code autonome.

Exercice : concevez trois routes avant d’en activer une

Sur papier (ou dans votre runbook), écrivez trois routes webhook pour votre environnement. Pour chacune, indiquez :

  • Nom
  • Source + filtre d’événement
  • Méthode d’authentification et propriétaire du secret
  • Champs de la charge utile : commencez par 10 au maximum comme budget d’exercice volontairement limité
  • Prompt : commencez par 8 lignes au maximum, puis n’ajoutez que ce qu’exigent les évaluations de la route
  • Outils autorisés
  • Cible de diffusion
  • Comportement en cas d’échec

N’implémentez d’abord que la route au risque le plus faible, généralement une alerte interne ou un résumé de PR limité au brouillon. Lancez curl sur /health, puis un POST de test authentifié et un test d’authentification invalide, puis un événement réel dans un dépôt hors production ou un projet de préproduction.

Modes d’échec à prévoir

  • Secret désynchronisé après rotation : l’authentification échoue ; corrigez l’environnement utilisé par le processus de passerelle, et pas seulement le shell de votre poste.
  • Prompt trop large : l’agent improvise des outils ; scindez la route.
  • Tempêtes de nouvelles tentatives : la source réessaie les POST. Hermes met en cache les ID de diffusion pendant une heure, mais une déduplication utile exige un X-GitHub-Delivery ou un X-Request-ID stable. Les actions visibles par le client nécessitent toujours une idempotence métier durable, dont la conservation correspond à la fenêtre de rejeu.
  • Pollution de la mémoire : des alertes volumineuses atteignent la mémoire durable ; utilisez un profil dédié et des paramètres de mémoire explicites.
  • Port exposé : le contrôle de santé et les webhooks sont accessibles sans les contrôles TLS et réseau prévus ; corrigez le réseau avant d’ajouter des outils.

Références à garder ouvertes

Les agents pilotés par événements sont utiles lorsque chaque route est étroite, authentifiée et observable, avec une cible de diffusion configurée. L’adaptateur webhook est une porte d’entrée pour les événements, et non l’API de requête/réponse authentifiée par jeton bearer. Concevez-le et testez-le en conséquence.

À lire ensuite

Continuez sur le même parcours d'apprentissage avec les prochains articles pratiques.

Pour aller plus loin

Des cours externes sélectionnés pour approfondir ce sujet.

Voir tous les cours pour Automations