/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 status affiche la cadence, les ticks déclenchés et le temps restant avant le prochain réveil ; /loop pause / resume / stop couvrent 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 :

  1. 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.
  2. État persistant : l’état de la boucle vit dans SessionDB.state_meta sous loop:<session_id>, si bien que /resume ramè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).
  3. Toutes les surfaces : CLI, TUI, dashboard, application de bureau et toutes les plateformes de messagerie du gateway — un loop_wakeup_watcher supervisé 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).
  4. La parenthèse Slack : Slack plafonne à 50 commandes slash, aussi Hermes a déplacé /version vers /hermes version pour 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.