Hermes Agent v0.20.3
Aperçu
v0.20.3 — Le patch de la résilience. Publié le 16 août 2026. ~125 PR fusionnées · ~250 commits · ~461 fichiers modifiés (+42,613 / −1,641) depuis v0.20.2.
Un jour après le patch des connexions, cette version répond à une question plus discrète : que se passe-t-il quand votre automatisation s’arrête en silence et que rien ne vous prévient ? L’ordonnanceur cron survit désormais à l’épuisement des descripteurs de fichiers, rapproche les claims obsolètes du ledger des exécutions, réarme les tâches récurrentes bloquées et rattrape les déclenchements manqués des providers externes — pendant que last_fire_error rend chaque manque visible dans la CLI, le dashboard et la sortie d’outils de l’agent lui-même. Autour de ce cœur : la migration vers le SDK MCP 2.x avec le support du protocole sans état du 2026-07-28, CommandCode comme fournisseur à part entière, /worktree et le /rollback sécurisé inspirés du CLI Copilot, le durcissement de la propriété du runtime Python des sous-processus, et les corrections de perte de données lors des handoffs de session.
Il s’agit d’un patch release, les notes officielles sont donc brèves et la documentation complète et organisée arrivera avec v0.21.0. Cette page couvre les parties les plus précieuses de cette fenêtre.
Points forts
1. L’ordonnanceur cron s’auto-répare
Trois modes de panne silencieuse qui laissaient autrefois des tâches mortes pendant des heures — alors que tout « semblait sain » — sont désormais auto-réparables :
- EMFILE (épuisement des descripteurs de fichiers) :
tick()avalait autrefois toutes lesOSErroren les prenant pour « une autre instance détient le verrou », si bien qu’un épuisement de fd sur le fichier de verrou était enregistré comme un tick réussi et qu’aucune tâche ne s’exécutait plus jamais. L’errno d’acquisition du verrou est désormais catégorisé : seule une véritable contention est ignorée en silence, les vraies pannes se propagent comme un tick en échec, et le ticker tente une récupération des fd au mieux (best-effort) (gc.collect()+ relèvement de la limite logicielle nofile) avec un backoff exponentiel plafonné à 15 minutes (#88335, basé sur #87796 de @webtecnica). - Claims en vol obsolètes : un claim fuité, plus jeune que la fenêtre d’âge (2×intervalle, 30 min), bloquait une tâche récurrente jusqu’à l’intervention d’un opérateur. Le balayage (sweep) opère désormais un rapprochement avec le ledger durable des exécutions : si la ligne terminale de l’exécution prouve qu’elle s’est terminée, le claim est libéré de force — avec une protection pour qu’un claim tout neuf ne soit jamais confondu avec le résultat final de l’exécution précédente (#88343, basé sur #87259).
- État d’erreur persisté bloqué : une tâche récurrente avec
last_status=erroretnext_run_atcalé dans le futur était invisible pour tous les balayages et survivait aux redémarrages du gateway. Elle se réarme désormais automatiquement au tick suivant — et le réarmement respecte la légalité du planning, si bien qu’une expression cron réservée aux jours de semaine ne se déclenche jamais un samedi (#88339, basé sur #87261).
2. Les déclenchements manqués sont visibles — et se rattrapent
L’incident en production du 14 août 2026 (4 déclenchements nocturnes manqués d’affilée, aucune trace en dehors d’une ligne de log) a produit deux correctifs durables. Premièrement, quand le chemin de déclenchement hébergé ne peut pas atteindre le gateway, la tâche reçoit une estampille last_fire_error affichée dans cronjob list, hermes cron list (ligne rouge ⚠ Missed scheduled fire:) et le dashboard ; une exécution réussie l’efface, si bien que l’estampille décrit toujours l’état de santé actuel (#88555). Deuxièmement, les providers cron externes (Chronos / cron managé hébergé) bénéficient désormais du rattrapage des déclenchements manqués : quand un déclenchement n’arrive jamais et que les tentatives sont épuisées, le gateway détecte la tâche en retard et l’exécute localement après un délai de grâce — cron.misfire_grace_minutes (défaut 10, ≤0 désactive). L’incident coûte des minutes au lieu d’une journée perdue en silence (#88563).
3. MCP : SDK 2.x + protocole sans état du 2026-07-28
Hermes a migré vers le SDK MCP 2.x (#88180) et parle désormais le protocole sans état du 2026-07-28 de bout en bout (#88299). Les serveurs sans handshake initialize se connectent sans configuration supplémentaire, via un point de passage unique _negotiate_session() sur les quatre sites d’appel de transport (stdio, SSE, nouveau HTTP, HTTP hérité). La clé protocol est configurable par serveur : auto (défaut) tente d’abord le handshake hérité et retombe sur server/discover quand le serveur le refuse — zéro aller-retour supplémentaire pour la flotte existante ; stateless sonde discover en premier ; legacy désactive le repli. Les indications SEP-2549 ttlMs/cacheScope issues de tools/list sont capturées dans le cache de schémas avec expiration par TTL, et l’enregistrement OAuth suit la nouvelle spécification (native application_type, validation iss RFC 9207).
4. Nouveaux fournisseurs : CommandCode (et Muse Spark sur main)
CommandCode (commandcode.ai) est désormais un fournisseur à part entière — les profiles commandcode (OpenAI chat completions) et commandcode-anthropic (Anthropic Messages, authentification Bearer) derrière une seule COMMANDCODE_API_KEY, couvrant les offres GOAT/Pro/Max/Provider (~30+ modèles ouverts et fermés, découverte en direct depuis l’endpoint public /provider/v1/models) (#88308, qui repêche #32909). Sur main (après le tag), l’API Meta Model (Muse Spark) arrive comme plugin intégré : --provider meta-ai fonctionne directement avec MODEL_API_KEY (alias META_API_KEY/META_MODEL_API_KEY, override via META_BASE_URL) et un catalogue muse-spark-1.2 / muse-spark-1.2-contributor (#88565).
5. /worktree et /rollback sécurisé — des modifications d’agent réversibles
Deux commandes inspirées du CLI Copilot débarquent dans cette fenêtre. /worktree new [name] crée un worktree git isolé en pleine session (.worktrees/ dans le dépôt, branche basée sur la pointe du remote fraîchement récupérée, worktree_sync respecté) et y redirige les outils de terminal et de fichiers de la session — sans redémarrage ; /worktree affiche l’arbre actif et /worktree list les énumère, avec le même nettoyage de sortie « conserver si non poussé » (keep-if-unpushed) que hermes -w. /rollback utilise désormais par défaut une restauration sécurisée : un ledger par projet des écritures de l’agent (sha256 de chaque write_file/patch appliqué) lui permet de n’annuler que ce que l’agent a modifié, de supprimer les fichiers créés par l’agent et de préserver vos modifications manuelles ; --all/--force restaure tout, et les fichiers ignorés sont signalés avec une indication.
6. Propriété du runtime Python des sous-processus
execute_code et consorts possèdent désormais leur environnement de sous-processus Python : PYTHONHOME/PYTHONPATH sont composés à partir du runtime géré, et non hérités contaminés du shell parent, ce qui élimine toute une classe de surprises du type « ça marche dans mon terminal, ça casse chez l’agent » et durcit la frontière pour le code non fiable.
7. Corrections de perte de données lors du handoff de session
Deux bugs de perte de données signalés par des utilisateurs sont corrigés (#88244). Une course CLI→gateway après /handoff telegram pouvait finaliser la ligne de session que le gateway était en train d’écrire, faisant disparaître tout le volet du handoff de l’historique et de session_search ; la CLI suit désormais les identifiants des sessions transférées et saute la finalisation de nettoyage. Par ailleurs, un state.db corrompu qui bloquait tous les messages est désormais signalé à l’utilisateur : le gateway diffuse des instructions de récupération (notamment hermes doctor --fix et sqlite3 .recover) vers les canaux d’accueil au lieu d’enterrer la panne dans les logs.
Améliorations
- Analyse de sécurité à l’installation et à la mise à jour des plugins (inspiré de Claude-Cowork) : les installations sont analysées à la recherche de contenu suspect avant activation.
- Les fichiers texte UTF-16 sont lus par transcodage vers UTF-8 (portage de MoonshotAI/kimi-code#2647) ; les identifiants d’appels d’outils Gemini 3 sont préservés à travers les réécritures d’adaptateur (portage de earendil-works/pi#7494).
- Auto-réparation des worktrees git : un
hermes -wen échec ou en timeout nettoie derrière lui (répertoire partiel, entrée admin LOCKED, branche orpheline), et la passe de maintenance au démarrage fait un repack quand les packs prolifèrent — les 39 packs (638 Mo) de l’incident d’août sont devenus 2 (287 Mo), et la création d’un worktree est passée d’un timeout de 30 s à 0,5 s (#88306). - Contrats de runtime Cua Driver 0.20 : computer use vérifie et répare automatiquement un driver installé qui échoue au contrat de runtime lors de la mise à jour comme à l’exécution (famille #87646).
- Bureau : le rendu DiffusionCanvas est borné (politique de pause, budget 15 fps, plafond d’instances), l’animation de l’œuf de pixels au repos s’endort, les discussions de groupe en Bot Mode affichent le Markdown, et les bureaux de gateways distants n’affichent plus un défaut local fantôme (#88564, #88406, #88553, #88554).
- Délégation : le travail non commité d’un sous-agent est conservé quand l’inspection git échoue, et les agents parents sont informés quand un worktree a été préservé sans avoir été inspecté.
Corrections
- Course
/handoffCLI→gateway perdant le volet du handoff (#88234) ; la corruption de state.db est désormais signalée avec des instructions de récupération (#88235). - Matrix : les noms de fichiers média vides ou nus issus des corps
m.audio/m.file/m.videosont éliminés ; Telegram privilégie les IP d’API IPv4 et journalise le sticker de premier choix en info. - Cron :
run_claimest effacé pour les tâches one-shot en cas d’échec de dispatch ; la remédiation de dérive est dirigée vers les pins appartenant à l’utilisateur. - Compression : une rotation avortée ne gonfle plus le parent qu’elle n’a pas pu publier.
- Bureau : l’attente de stabilisation avant démarrage ne peut plus verrouiller le composer en position fermée ; un bras de restauration/édition maintient le composer utilisable.
Mise à jour
hermes update
Après la mise à jour, lancez hermes doctor pour vérifier l’installation et redémarrez le gateway (hermes gateway) pour que les changements de plateforme prennent effet. Si vous utilisez un provider cron externe, exécutez une fois hermes cron list pour confirmer que last_fire_error n’affiche rien en attente.