/loop : les réveils récurrents en session de Hermes — timer-driven, ni judge-driven, ni cron

Le script de déploiement est terminé, mais vous n’osez pas vous éloigner — le CI va-t-il passer au rouge ? La file d’attente va-t-elle s’engorger ? Quand le service sera-t-il réellement en ligne ? Alors vous actualisez la page toutes les cinq minutes, comme une sentinelle dévouée.
La toute nouvelle commande /loop de Hermes existe pour vous décharger de ce tour de garde : relancer un prompt à une cadence récurrente dans votre session, en se réveillant à chaque tick pour travailler sur l’état courant. C’est la réponse de Hermes au /loop de Claude Code (l’alias /proactive fonctionne aussi ici), tout juste fusionnée dans main. Cet article l’explique en profondeur : ce qui la distingue fondamentalement de /goal et de cron, et comment l’utiliser concrètement.
Trois commandes, trois moteurs
| Commande | Moteur | Cycle de vie | Usage typique |
|---|---|---|---|
/goal |
Judge-driven — après chaque tour, un modèle juge vérifie « est-ce terminé ? » et Hermes continue tant que non | Session unique, sur plusieurs tours | « Corrige toutes les erreurs de lint dans src/ et vérifie que le contrôle passe » |
/loop |
Timer-driven — se réveille à la cadence définie, fait le travail, jusqu’à ce que quelque chose dise stop | Session unique, sur plusieurs tours et sur plusieurs reprises | « Vérifie le déploiement toutes les 5 minutes et dis-moi quand il est en ligne » |
| cron | Schedule-driven — un horaire fixe, sans session impliquée | Hors de toutes les sessions, sans surveillance | « Publie un digest quotidien sur le canal à 9h » |
/goal signifie « continue de travailler jusqu’à ce que l’objectif soit atteint », /loop signifie « continue de vérifier jusqu’à ce que quelque chose dise stop », cron signifie « s’exécuter selon un planning, sans lien avec la conversation ». Trois outils qui ne se chevauchent pas.
Deux modes de cadence : à vous de régler l’horloge, ou elle se règle toute seule
Intervalle fixe — votre horloge
/loop 5m check the deploy status and tell me if it's live yet
Toutes les 5 minutes (tant que la session est inactive), Hermes injecte un véritable tour d’agent sur l’état courant — le dernier résultat CI, la profondeur de file la plus récente, le fichier tel qu’il est à l’instant présent.
Self-paced — plus il attend, plus il devient malin
Omettez l’intervalle et Hermes se règle tout seul :
/loop keep an eye on the migration and summarize progress
Le mécanisme est astucieux : la cadence démarre au plancher de 60 secondes et, tant que les réponses de l’agent cessent de changer, elle applique un backoff exponentiel (2 min → 4 min → 8 min … jusqu’au plafond de 15 minutes). Dès qu’une réponse diffère, la cadence revient instantanément au plancher. La détection de changement repose sur une comparaison de digest locale, insensible aux horodatages — zéro coût LLM supplémentaire. Plus les choses sont calmes, moins il vous dérange ; dès qu’il y a du progrès, il redouble d’attention.
Règle empirique : intervalle fixe quand une horloge externe pilote le travail ; self-paced quand c’est le travail qui impose le rythme.
Conditions d’arrêt : cinq sorties
| Condition | Comment |
|---|---|
| L’agent décide que c’est terminé | Les réponses de réveil se terminant par LOOP_COMPLETE sur sa propre ligne |
| Un plafond de passages | --times N (ex. --times 30) |
| Une condition fondée sur des preuves | --until <condition> — évaluée par le même juge auxiliaire qui alimente /goal (fail-open : un juge défaillant ne bloque jamais la boucle) |
| Vous | /loop stop (ou /loop pause pour la garder en vie) |
| Le budget de sécurité | loops.max_ticks (100 par défaut ; 0 = illimité) pour qu’une session sans surveillance ne brûle pas des tokens indéfiniment |
/loop 2m poll CI --times 30
/loop 5m watch the queue --until "queue depth reaches zero"
Contrôle et composition
/loop statusaffiche la cadence, les ticks déclenchés et le temps restant avant le prochain réveil ;/loop pause/resume/stopcouvrent tout le cycle de vie (Ctrl+C pendant un réveil met la boucle en pause, récupérable via/loop resume).- Bouclez une commande slash tout aussi facilement :
/loop 10m /recap. - Travailler avec
/goal: un goal actif, non parké, détient la frontière d’inactivité — les ticks de la boucle attendent que le goal se termine, se mette en pause ou se parke (une wait barrier). Un goal parké associé à un heartbeat de boucle se compose naturellement. Une vraie saisie utilisateur prime toujours sur les deux — dès que vous tapez, les deux s’effacent.
Pourquoi elle ne plante pas : l’architecture
C’est la partie qui vaut vraiment la peine d’être comprise — /loop n’est pas une boucle while true :
- Injection d’un tour user-role ordinaire : chaque réveil est un message user-role normal. Aucune mutation du system prompt, aucun changement de jeu d’outils, le prompt cache reste intact — boucler ne détruit pas votre cache ni ne gaspille de tokens.
- État persistant : l’état de la boucle vit dans
SessionDB.state_metasousloop:<session_id>, si bien que/resumeramène la boucle, et il migre à travers la compression de contexte (même mécanisme que/goal, avec le risque connu corrigé de façon préventive). - Toutes les surfaces : CLI, TUI, dashboard, application de bureau et toutes les plateformes de messagerie du gateway — un
loop_wakeup_watchersupervisé scanne les boucles persistées et injecte les réveils arrivés à échéance dans les conversations inactives, même pendant votre absence. C’est quelque chose que Claude Code ne peut pas faire (sa boucle meurt avec la session CLI). - La parenthèse Slack : Slack plafonne à 50 commandes slash, aussi Hermes a déplacé
/versionvers/hermes versionpour libérer un emplacement natif pour/loop.
Comparaison avec le /loop de Claude Code
| Claude Code | Hermes | |
|---|---|---|
| Surfaces | Session CLI uniquement | CLI, TUI, dashboard, bureau, toutes les plateformes de messagerie |
| Persistance | Meurt avec la session | Survit à /resume et à la compression de contexte |
| Rythme self-paced | Décidé par le modèle | Backoff de digest local (gratuit, déterministe) |
| Conditions d’arrêt | Intégrées au prompt | LOOP_COMPLETE + --times + --until jugé + budget de sécurité |
| Interaction avec /goal | Fonctionnalités séparées | Priorité explicite : le goal actif détient la frontière d’inactivité |
Lequel choisir ?
- Surveiller un état externe (déploiement, CI, file d’attente, taux d’erreurs) →
/loop(fixe ou self-paced) - Un objectif mené à bien (corriger tous les lints, passer le CI au vert) →
/goal(voir Heartbeats, Refinement & Goal Gates) - Des tâches planifiées sans surveillance (digests quotidiens, exécutions nocturnes) → cron (guide complet : The Hermes Cron Automation Guide)
Statut de la version et comment l’obtenir
/loop a été fusionnée dans main le 14 août 2026 (PR #72333, avec 77 nouveaux tests + 367 tests de régression + 22 tests de bureau, tous au vert). Elle n’est encore dans aucune version officielle (la plus récente reste v0.20.1). Pour l’essayer :
- Attendez la prochaine version et lancez
hermes update; - Ou installez dès maintenant depuis main :
hermes update --branch main(revenir en arrière une fois la version publiée).
Clés de configuration optionnelles : loops.min_interval_seconds, loops.max_ticks, loops.self_paced_floor_seconds, loops.self_paced_ceiling_seconds.
Pour conclure
/loop retire la « surveillance » de vos actualisations manuelles : intervalles fixes pour les horloges externes, cadence self-paced qui devient plus maligne à mesure qu’elle attend (backoff quand c’est stable, redoublement d’attention quand ça change — à coût LLM nul), persistance et couverture de toutes les plateformes qui surpassent l’original de Claude Code, et coopération explicite avec /goal. Au prochain déploiement, confiez-lui le tour de garde.