Aller au contenu

Hermes : les plugins et leurs hooks

Les skills sont du texte : elles orientent le modèle. Les plugins sont du code Python : ils s’exécutent, qu’importe ce que le modèle décide.

Un plugin s’enregistre sur des hooks du cycle de vie de Hermes et peut, selon le hook, observer un événement, réécrire un message avant traitement, ou exposer de nouveaux outils à l’agent.

PluginVersionApportAuteur
telegram-voice-transcriptor1.1.0Hook pre_gateway_dispatchSur mesure
telegram-message-editor1.0.0Outil telegram_status_messageSur mesure
codex-usage-alert1.0.0Hook post_api_requestSur mesure
mnemosyne0.4.020 outils + 3 hooksTiers (Abdias J)
HookMomentPeut faire
pre_gateway_dispatchMessage reçu, avant traitementRéécrire ou rediriger l’événement
pre_llm_callAvant l’appel au modèleInjecter du contexte dans le prompt
on_session_startOuverture de sessionCharger un état initial
post_tool_callAprès un appel d’outilObserver, capturer
post_api_requestAprès un appel LLM aboutiObserver, déclencher un effet de bord

Pourquoi des plugins user plutôt qu’un patch du cœur ?

Section intitulée « Pourquoi des plugins user plutôt qu’un patch du cœur ? »

L’arbre applicatif /opt/hermes appartient à l’image. Une modification y survit jusqu’à la prochaine mise à jour — et disparaît alors sans bruit, ce qui est la pire des fins pour une personnalisation.

Les plugins user vivent dans /opt/data/plugins/, c’est-à-dire dans le bind mount. Ils survivent aux docker compose up --force-recreate comme aux mises à jour d’image, et partent dans le backup quotidien.

C’est la même règle que le mode wrapper de Mnemosyne : tout ce qui doit durer vit dans le volume, jamais dans l’image.

Les deux ajoutent des capacités, mais pas au même endroit ni au même prix.

Outil MCP N8NPlugin
Un node dans un workflowDu Python dans le conteneur
AccèsCe que N8N peut atteindreLe runtime de Hermes lui-même
ModificationÉditer le workflow, redémarrer le conteneurÉditer le fichier, redémarrer le conteneur
Peut réagir à un événementNon — seulement être appeléOui, via les hooks

La ligne de partage est simple : une action métier devient un outil MCP ; un comportement qui doit se déclencher sans que l’agent le décide devient un plugin.


Sur un vocal Telegram, le plugin réécrit l’événement pour y injecter le bloc de la skill transcriptor-fr-voice. Le pipeline STT préfixe ensuite le transcript en citation, et l’agent répond avec le texte français nettoyé.

Son intérêt tient moins à ce qu’il fait qu’à ce sur quoi il refuse de se déclencher.

Le hook est aussi fail-open : toute exception est journalisée en avertissement et le message part en traitement normal. Une skill cassée ou un import raté ne doit jamais avaler un message vocal.

Ce plugin expose un outil, telegram_status_message, avec deux actions : create envoie un message et retourne son message_id, update édite ce même message en place. Plafond 4096 caractères, et par défaut la conversation courante quand l’appel vient de Telegram.

Le problème qu’il résout est un problème d’ergonomie. Un agent qui travaille plusieurs minutes sur une tâche en plusieurs étapes a le choix entre se taire — et laisser croire qu’il est bloqué — ou envoyer un message par étape, et noyer la conversation. L’édition en place donne un troisième choix : un tableau de bord unique qui se met à jour.

Hermes partage l’abonnement ChatGPT avec CLI Ollama et les workflows N8N. Atteindre le plafond hebdomadaire ne produit aucun signal avant que le bot ne se mette à répondre par des erreurs.

Le plugin s’enregistre sur post_api_request, ne réagit qu’aux appels du provider openai-codex, et alerte quand la consommation du compte franchit un seuil (90 % par défaut).

Ses quatre garde-fous méritent d’être notés, parce qu’ils sont ce qui distingue un plugin d’observation acceptable d’un plugin qui dégrade le service :

Garde-fouMise en œuvre
Non bloquantLe hook démarre au plus un thread démon court et rend la main immédiatement
Charge maîtriséeUn cooldown de 300 s évite de rappeler le backend à chaque message d’une conversation active
Anti-spamUne alerte par combinaison seuil + fenêtre de quota + heure de reset, avec un historique borné à 200 clés
Fail-openToute erreur est journalisée et n’affecte jamais la réponse de Hermes

Le principe commun : un plugin greffé sur un chemin chaud ne doit jamais être ce qui casse ou ralentit la réponse.

Le seul plugin tiers du lot, et de loin le plus gros : 20 outils et 3 hooks (pre_llm_call, on_session_start, post_tool_call). Il est installé en mode wrapper et fait l’objet d’un article dédié.

Sa présence dans cette liste dit quelque chose du système d’extension : la mémoire longue, qui est sans doute la fonctionnalité la plus structurante de l’agent, s’installe par le même mécanisme qu’une alerte de quota.

Un plugin est un répertoire avec un plugin.yaml et un __init__.py qui expose register(ctx).

def register(ctx) -> None:
ctx.register_hook("post_api_request", _on_post_api_request)
name: codex-usage-alert
version: 1.0.0
description: "Non-blocking Telegram Home alert when OpenAI Codex account usage crosses a threshold."
author: Guillaume PARRAT + Hermes Agent
provides_hooks:
- post_api_request

Seul telegram-voice-transcriptor a une source versionnée dans le dépôt ; le déploiement se fait par copie puis redémarrage :

Fenêtre de terminal
cp -r ai-stack/hermes/plugins/telegram-voice-transcriptor ai-stack/hermes/data/plugins/
docker compose -f ai-stack/docker-compose.yaml restart hermes
docker exec hermes hermes plugins list # statut attendu : enabled

LimiteImpactMitigation
Trois plugins sur quatre non versionnésSeul le transcripteur a une source dans le dépôt ; les autres n’existent qu’en productionSauvegarde quotidienne ; portage vers le dépôt à faire
Redémarrage obligatoireToute modification impose un restart du conteneurRegrouper les changements
Pas de test automatiséUn plugin cassé se découvre à l’usageLe fail-open limite les dégâts à une fonctionnalité perdue
Hooks non versionnés côté amontUn changement de signature amont casse un pluginhermes plugins list après chaque mise à jour d’image
Pas d’isolationUn plugin s’exécute dans le processus du gatewayDiscipline : non bloquant et fail-open par défaut

Si les plugins doivent être versionnés :

  • ai-stack/hermes/plugins/ existe déjà et contient le transcripteur — les trois autres suivent le même patron.
  • Bénéfice principal : pouvoir revenir en arrière après une mise à jour amont qui casse un hook.

Si un plugin doit devenir bloquant :

  • Le cas typique serait une vraie chaîne d’approbation avant les actions sensibles, plutôt que la règle de system prompt actuelle.
  • Un hook pre_tool_call conviendrait — mais un plugin bloquant sur le chemin chaud demande un timeout et un comportement de repli explicites, sinon une panne du plugin gèle l’agent.

Si l’observabilité doit progresser :

  • post_api_request et post_tool_call sont les points naturels pour exporter des métriques.
  • Un plugin qui pousserait un compteur vers Prometheus donnerait à Hermes la même visibilité que le reste des stacks dans Grafana.

  • Hermes Agent — Le déploiement et l’activation des plugins
  • Mémoire Mnemosyne — Le plus gros plugin du lot
  • Skillshermes-user-plugins et hermes-runtime-plugins, l’outillage d’écriture
  • Outils MCP — L’autre façon d’ajouter une capacité