Aller au contenu

Hermes Agent : un agent autonome sur Telegram

Hermes Agent est un agent conversationnel autonome publié par Nous Research sous licence MIT. Contrairement aux briques IA déjà en place sur le VPS — qui sont des passerelles appelées par des workflows — Hermes est un processus long qui garde le fil : il conserve sa mémoire entre les conversations, choisit lui-même quels outils appeler, et n’a besoin d’aucun workflow pour décider quoi faire.

Sur cette infrastructure, il tourne dans un conteneur de l’ai-stack avec un bot Telegram dédié comme seule interface. Aucun port publié, aucune route Caddy, aucun dashboard.

BriqueDétail
Conteneurnousresearch/hermes-agent:latest — aucun port publié, réseaux n8n-internal + mcp-backend
LLMAbonnement ChatGPT/Codex via le provider natif openai-codex (gpt-5.5)
Outils métier32 outils MCP servis par le workflow N8N Hermes MCP Tools
Outils debug4 outils N8N en lecture seule (n8n-mcp), réservés au diagnostic de workflows
MémoireProvider externe Mnemosyne — SQLite local, recherche hybride vecteur + FTS5
Plugins3 plugins maison greffés sur les hooks du gateway

N8N

Conteneur hermes · aucun port publié

Bearer · flow normal · 32 outils

Bearer · debug uniquement

MCP stdio · hors N8N

Cibles métier

Odoo · projets, tâches, contacts, CRM, timesheets

Docker · status, logs, start/stop/restart

Prometheus · alertes, PromQL

Vault Obsidian vps-vault · lecture + écriture confinée

Telegram · bot dédié · allowlist stricte

Gateway Hermes · gpt-5.5 via openai-codex

Mnemosyne · SQLite + FTS5 · /opt/data

Plugins · voice, message editor, usage alert

MCP Server Trigger · /mcp/hermes-tools

n8n-mcp · 4 outils diagnostic

Plaud · serveur MCP officiel · stdio

Cet article couvre le déploiement : conteneur, configuration, modèle de sécurité et exploitation. Trois articles détaillent ce qui s’y greffe.

ArticleContenu
Les 32 outils MCPCatalogue complet, gateways à entrées typées, écriture confinée dans le vault, pièges de la couche MCP N8N
La mémoire longue MnemosyneMode wrapper, recherche hybride, 20 outils de mémoire, consolidation et exploitation
Les skills sur mesureLe système de skills et les douze procédures écrites pour ce déploiement
Les plugins et leurs hooksQuatre plugins Python greffés sur le cycle de vie du gateway

Prises en session de cadrage avant la première ligne de configuration, elles expliquent la quasi-totalité de la forme du déploiement.

DécisionRaison
LLM en direct via openai-codex, sans passer par cli-ollamaL’abonnement est consommé nativement par le provider Hermes. Interposer la passerelle ajouterait un saut, un timeout et une perte de contexte pour zéro gain
Accès N8N en double canalUn canal d’outils métier curés, un canal de diagnostic en lecture seule. La séparation est explicite, pas implicite
Bot Telegram uniquementPas de port, pas de route Caddy, pas de dashboard : la surface d’attaque HTTP est nulle
Service dans ai-stack/docker-compose.yamlCohabitation avec Qdrant et cli-ollama, mêmes réseaux internes, même cycle de vie
Réactif seulement en v1Le scheduler et les automations restent désactivés : un agent qui agit sans qu’on le lui demande est difficile à auditer tant qu’on n’a pas confiance dans ses garde-fous
Data dir dans le backup quotidienToute la valeur accumulée (mémoire, sessions, skills) vit dans un seul répertoire — le perdre, c’est repartir de zéro

Le serveur MCP administrateur (n8n-mcp) expose 24 outils, dont n8n_delete_workflow et n8n_manage_credentials. Les brancher tels quels reviendrait à donner à l’agent les clés de l’automatisation entière pour lui permettre de lire un log d’exécution.

Le déploiement les sépare donc :

  • n8n-tools — le flow normal. Des outils métier écrits à la main, à entrées typées, exposés par un workflow N8N dédié. C’est ce que l’agent utilise 99 % du temps.
  • n8n-admin — filtré à 4 outils de diagnostic en lecture seule (n8n_list_workflows, n8n_get_workflow, n8n_executions, n8n_validate_workflow), et réservé par une règle du system prompt au seul débogage de workflows.

La mémoire native de Hermes est un fichier MEMORY.md réinjecté dans le prompt. Simple, mais elle plafonne : pas de recherche, et un budget de caractères qui force à arbitrer entre tout garder et rester lisible.

Mnemosyne remplace ce mécanisme par une base SQLite locale avec recherche hybride (vecteur + FTS5) et capture en tâche de fond à chaque tour. Local-first : aucune donnée de conversation ne quitte le VPS pour être vectorisée.


hermes:
image: nousresearch/hermes-agent:latest
container_name: hermes
command: gateway run
networks:
- n8n-internal # MCP Server Trigger (n8n:5678)
- mcp-backend # n8n-mcp:3000 (debug uniquement)
environment:
- PUID=${CLAUDE_USER_ID:-1000}
- PGID=${CLAUDE_GROUP_ID:-1000}
- TELEGRAM_BOT_TOKEN=${HERMES_TELEGRAM_BOT_TOKEN}
- TELEGRAM_ALLOWED_USERS=${HERMES_ALLOWED_CHAT_ID}
- HERMES_N8N_MCP_TOKEN=${HERMES_N8N_MCP_TOKEN}
- N8N_MCP_AUTH_TOKEN=${N8N_MCP_AUTH_TOKEN}
volumes:
- ./hermes/data:/opt/data
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- CHOWN
- SETUID
- SETGID
- DAC_OVERRIDE
deploy:
resources:
limits:
memory: 3G
cpus: '2'
healthcheck:
test: ['CMD-SHELL', 'pgrep -f "bin/hermes[ ]gateway run" > /dev/null || exit 1']
interval: 30s

Aucune section ports : c’est volontaire et c’est le cœur du modèle de sécurité. Le seul chemin entrant est le long-polling Telegram sortant.

Hermes génère et migre son config.yaml tout seul au premier démarrage ; seules les clés de ce déploiement sont reportées à la main.

model:
provider: "openai-codex"
default: "gpt-5.5"
base_url: "https://chatgpt.com/backend-api/codex"
mcp_servers:
n8n-tools: # flow normal
url: "http://n8n:5678/mcp/hermes-tools"
headers:
Authorization: "Bearer ${HERMES_N8N_MCP_TOKEN}"
timeout: 120
n8n-admin: # debug de workflows UNIQUEMENT
url: "http://n8n-mcp:3000/mcp"
headers:
Authorization: "Bearer ${N8N_MCP_AUTH_TOKEN}"
tools:
include: [n8n_list_workflows, n8n_get_workflow, n8n_executions, n8n_validate_workflow]
memory:
provider: "mnemosyne"
plugins:
enabled:
- telegram-voice-transcriptor
gateway:
platforms:
telegram:
extra:
allow_from:
- "<CHAT_ID>" # valeur LITTÉRALE obligatoire

Certaines règles ne peuvent pas être imposées par la plomberie : elles vivent dans SOUL.md, occupant le premier slot du system prompt.

  • Flow normal : toute action métier passe par n8n-tools.
  • n8n-admin = debug uniquement, jamais pour une action métier, et jamais pour modifier un workflow.
  • docker_manage = action sensible : aucune chaîne d’approbation n’existe en aval, donc l’agent doit demander une confirmation explicite avant chaque start/stop/restart/update, en nommant la stack et l’action.
  • Vault : toujours citer le chemin du fichier source ; écriture uniquement via vault_write, confinée, et jamais de sa propre initiative.
  • Pas d’action non sollicitée : l’agent exécute ce qui est demandé et propose le reste.

Trois mécanismes d’extension cohabitent, et la distinction entre eux structure tout le déploiement.

MécanismeNatureOù il vitDétail
Outils MCPNodes N8NWorkflow Hermes MCP Tools32 outils sur 8 domaines
SkillsMarkdown/opt/data/skills/145 actives, dont 12 sur mesure
PluginsPython/opt/data/plugins/4 plugins, greffés sur les hooks

La règle de partage : un outil MCP rend une action possible, une skill la rend bien faite, un plugin la déclenche sans que l’agent décide. Et la mémoire longue — Mnemosyne — s’installe par le troisième mécanisme, en mode wrapper.

SurfaceProtection
Endpoint MCP N8NBearer obligatoire — 403 sans token, vérifié en E2E
Endpoint MCP depuis Internet/mcp/* et /mcp-test/* renvoient 404 côté Caddy ; seul le chemin interne n8n:5678 fonctionne
Bot TelegramAllowlist stricte fail-closed — un chat_id inconnu est bloqué sans réponse
Actions destructrices DockerWhitelist d’actions dans Docker Actions, security-stack non actionnable
docker_manage, crm_delete_lead, timesheet_deletePas de chaîne d’approbation en aval → confirmation exigée par le system prompt
Écriture vaultConfinée à research/ et inbox/, extension .md, anti-traversal, plafond 150 000 octets
SecretsPassés par l’environnement compose, jamais écrits dans /opt/data (qui part en backup)

Le confinement de vault_write mérite un mot, parce qu’il résout un problème classique des agents qui écrivent : l’écrasement à l’aveugle. Une lecture via vault_read renvoie un contentHash ; modifier un fichier existant exige de repasser ce hash en Base_Hash. Sans hash, la réponse est __EXISTS__ ; si le fichier a bougé depuis la lecture, __STALE_READ__. Et les erreurs ne renvoient jamais le hash courant — sinon le modèle pourrait le récupérer et écraser sans avoir lu. Détail de l’implémentation.

Le répertoire de données part dans le backup quotidien vers Google Drive, après exclusions : les credentials OAuth (auth.json, google_token.json, google_client_secret.json), les credentials Git, le venv Mnemosyne et les caches de modèles. La base de mémoire, elle, est incluse. L’archive tombe ainsi à 8,2 Mo au lieu de 58 Mo.

Après une restauration complète, trois gestes manuels : refaire le device flow Codex, refaire le flow OAuth Google, réinstaller le venv Mnemosyne.

Fenêtre de terminal
docker exec hermes hermes mcp test n8n-tools # connexion MCP live + liste d'outils
docker exec hermes hermes auth list # credential OAuth chargé ?
docker exec hermes hermes plugins list # plugins enabled/disabled
docker exec hermes hermes memory status # provider mémoire actif
docker exec hermes hermes gateway status
docker exec hermes hermes -z "ping" # tour LLM one-shot (consomme du quota)

LimiteImpactMitigation
Quota ChatGPT partagéL’abonnement sert Hermes, Codex CLI et les workflows N8N. Plafond atteint = le bot renvoie des erreurs jusqu’au resetPlugin codex-usage-alert sur seuil ; router les usages non interactifs vers gemini-flash
Garde-fous portés par le promptdocker_manage et les suppressions n’ont pas de validation technique en avalWhitelist d’actions dans Docker Actions ; une vraie chaîne d’approbation Telegram reste à câbler
v1 réactiveAucune tâche planifiée : l’agent ne fait rien sans sollicitationVolontaire tant que les garde-fous ne sont pas durcis
employee_id figétimesheet_log_hours écrit toujours sur l’employé 1Sans objet aujourd’hui (un seul employé), à paramétrer si l’équipe grandit
Mapping des étapes CRMLes IDs d’étapes sont encodés dans les descriptions $fromAIcrm_list_stages fournit désormais la source dynamique
Sous-nodes MCP non désactivablesDésactiver un outil dans Hermes MCP Tools fait exécuter le mauvais node à tous les outils suivants, en silenceSupprimer le node plutôt que le désactiver (détail)

Si l’agent devient proactif :

  • Déposer des jobs dans /opt/data/cron/ active le scheduler (inactif tant qu’il est vide).
  • Prérequis : une chaîne d’approbation réelle sur les actions sensibles, pas seulement une règle de prompt.
  • Candidats naturels : digest matinal des alertes Prometheus, relance des leads CRM dormants.

Si la mémoire doit sortir du VPS :

  • Export des mémoires Mnemosyne en notes markdown dans le vault, pour les rendre lisibles et versionnées.
  • Puis synchronisation bidirectionnelle VPS ↔ poste de travail, pour une mémoire unique entre l’agent et l’assistant local. Détail.

Si le périmètre d’écriture s’élargit :

  • Le confinement research/ + inbox/ est une liste blanche de préfixes : l’étendre est trivial, mais chaque nouveau préfixe doit venir avec sa justification.
  • La séquence commit + push immédiat propage déjà vers les clients Obsidian ; augmenter le débit d’écriture augmentera le bruit dans l’historique Git.

Si un second utilisateur doit y accéder :

  • L’allowlist accepte plusieurs chat_id, mais la mémoire et le profil utilisateur sont globaux au conteneur.
  • Il faudrait un conteneur par utilisateur (répertoires de données distincts) plutôt qu’une allowlist élargie.
Fenêtre de terminal
# Le bot ne répond pas
docker logs hermes --tail 100
docker inspect hermes --format='{{.State.Health.Status}}'
# Message ignoré → allowlist
docker logs hermes 2>&1 | grep -i "unauthorized"
# Outils MCP absents ou périmés
docker exec hermes hermes mcp test n8n-tools
docker compose -f ai-stack/docker-compose.yaml restart hermes
# Mémoire indisponible
docker exec hermes hermes memory status
docker exec --user hermes -e HOME=/opt/data -e HERMES_HOME=/opt/data hermes \
/opt/data/.mnemosyne/venv/bin/mnemosyne stats
# Vérifier que l'endpoint MCP reste bien fermé de l'extérieur
curl -so /dev/null -w '%{http_code}\n' https://n8n.guigpap.com/mcp/hermes-tools # attendu : 404

  • Glossaire — MCP, Agent autonome, Mémoire à long terme, LLM