📑 Table des matières

18 - Code Execution et Checkpoints dans Hermes Agent

Hermes Agent 🔴 Avancé ⏱️ 11 min de lecture 📅 2026-05-05

Introduction

Hermes Agent ne se contente pas d'exécuter des commandes shell. Il dispose de deux mécanismes puissants pour l'exécution de code et la gestion des modifications de fichiers : Code Execution (exécution de scripts Python avec accès aux outils Hermes) et Checkpoints (snapshots automatiques du filesystem pour rollback). Ces features transforment Hermes en un environnement de développement véritablement sécurisé, où chaque modification peut être annulée et chaque script complexe s'exécute de manière isolée.

Prenons un exemple concret : vous demandez à l'agent de refactoriser un module d'authentification, de mettre à jour les tests, et de générer la documentation. Sans Code Execution, cela représente 15 à 20 appels d'outils séparés, chacun consommant des tokens de contexte. Avec Code Execution, l'agent écrit un script Python qui fait tout en un seul tour. Et si le résultat n'est pas bon ? Les Checkpoints vous permettent de revenir en arrière d'un simple /rollback.

Cet article détaille ces deux fonctionnalités, leur configuration, et comment les combiner pour un workflow de développement optimal.

Code Execution : exécuter du Python avec les outils Hermes

Le concept

L'outil execute_code permet au modèle IA d'écrire et d'exécuter un script Python qui peut appeler les outils Hermes (terminal, lecture/écriture de fichiers, recherche, patch, web). C'est ce qu'on appelle le Programmatic Tool Calling (PTC).

Le problème qu'il résout : quand une tâche nécessite de lire plusieurs fichiers, de les traiter, et d'écrire des résultats, l'agent ferait normalement un appel d'outil par étape — lire, puis traiter mentalement, puis écrire, puis relire, etc. Chaque appel consomme des tokens de contexte et un tour de conversation. execute_code collapse toute la chaîne en un seul appel : l'agent écrit un script Python complet, le script appelle les outils via RPC, et seul le résultat final est retourné au LLM.

Architecture : le processus parent génère un module hermes_tools.py avec des stubs RPC, puis lance le script dans un processus enfant. Les appels d'outils transitent via un socket Unix (exécution locale) ou des fichiers (exécution distante via Docker/SSH) vers le parent qui les dispatch. Seul le stdout du script est retourné au LLM — les résultats intermédiaires des appels d'outils n'encombrent pas le contexte.

Outils disponibles dans le sandbox

Les scripts execute_code ont accès à un sous-ensemble strict d'outils Hermes :

Outil Description
read_file Lire des fichiers
write_file Écrire des fichiers
search_files Chercher dans les fichiers (contenu et noms)
patch Modifications ciblées (find-and-replace)
terminal Exécuter des commandes shell
web_search Recherches web
web_extract Extraction de contenu web

L'intersection entre cette liste et les toolsets activés de la session détermine les stubs réellement générés. Si web n'est pas activé dans votre session, web_search et web_extract ne seront pas disponibles dans les scripts.

Notez l'absence volontaire d'outils à effet externe : send_message, delegate_task, clarify, memory, et code_execution lui-même ne sont pas disponibles. Le script ne peut pas envoyer de messages, déléguer des tâches, ou créer des sous-agents.

Les deux modes d'exécution

Mode project (défaut) : le script s'exécute dans le répertoire de travail de la session avec le Python de l'environnement virtuel actif. Les dépendances du projet (pandas, numpy, requests, packages installés dans le venv) et les chemins relatifs fonctionnent normalement. C'est le mode à utiliser pour la majorité des tâches de développement.

Mode strict : le script s'exécute dans un répertoire temporaire isolé avec le Python de Hermes lui-même (sys.executable). Isolation maximale et reproductibilité parfaite, mais les dépendances du projet et les chemins relatifs ne fonctionnent pas. Utile pour les scripts autonomes qui n'ont pas besoin de packages externes.

# Dans ~/.hermes/config.yaml
code_execution:
  mode: project    # project (défaut) | strict

Limites et sécurité

Le sandbox applique automatiquement plusieurs couches de protection :

Scrubbing des variables d'environnement : les variables contenant API_KEY, TOKEN, SECRET, PASSWORD, CREDENTIAL sont automatiquement supprimées de l'environnement du processus enfant. Même si l'agent essaie d'accéder à os.environ['OPENROUTER_API_KEY'] dans un script, la variable ne sera pas là. Cette protection est non-contournable — elle s'applique avant le lancement du processus.

Whitelist d'outils : seuls les 7 outils listés ci-dessus sont disponibles. Pas d'accès à send_message, delegate_task, memory, ou tout outil pouvant avoir des effets externes irréversibles.

Limites de ressources :
- Timeout : 5 minutes par défaut (300 secondes)
- Max tool calls : 50 appels d'outils par script
- Taille de stdout : 50 Ko maximum
- Taille de stderr : 10 Ko maximum

Si le stdout dépasse 50 Ko, seuls les 500 premiers octets et les 500 derniers sont retournés (head + tail), ce qui permet de voir le début et la fin de la sortie sans saturer le contexte.

Restriction de plateforme : le sandbox nécessite les sockets Unix (POSIX), donc Linux et macOS uniquement. Désactivé automatiquement sur Windows.

Fonctions utilitaires intégrées

Le module hermes_tools injecté dans chaque script fournit des helpers spécifiques :

from hermes_tools import terminal, read_file, write_file, search_files, patch

# Fonctions utilitaires
from hermes_tools import json_parse, shell_quote, retry

# json_parse — équivalent de json.loads tolérant les caractères de contrôle
# Utile pour parser la sortie de commandes shell qui contient des ANSI codes
data = json_parse(raw_output)

# shell_quote — échappement shell sécurisé pour les variables dynamiques
cmd = f"grep {shell_quote(user_input)} /var/log/app.log"

# retry — retry avec backoff exponentiel pour les opérations réseau
result = retry(fetch_api, max_attempts=3, delay=2)

La fonction terminal() dans les scripts est foreground uniquement — pas de background ni de PTY. Elle retourne un dict avec output, exit_code, et éventuellement error.

Quand l'agent déclenche-t-il execute_code ?

L'agent décide automatiquement d'utiliser execute_code quand une tâche nécessite 3+ appels d'outils avec du traitement logique entre eux. Exemples typiques :

  • Pipeline de données : lire 5 fichiers JSON, filtrer par critères, agréger les résultats, écrire un rapport
  • Recherche multi-fichiers : chercher un pattern dans 10 fichiers, extraire les lignes correspondantes, synthétiser
  • Boucles conditionnelles : fetch N pages web, parser chaque réponse, accumuler les résultats, arrêter si une condition est remplie
  • Transformations complexes : lire un CSV de 1000 lignes, calculer des métriques par groupe, générer un fichier de sortie formaté
  • Mises à jour en masse : lire une liste de fichiers, appliquer un remplacement identique à chacun, vérifier la syntaxe

Pour les tâches simples (un seul appel d'outil, pas de logique intermédiaire), l'agent préfère les appels d'outils directs — c'est plus rapide et tout aussi efficace.

Checkpoints : snapshots automatiques du filesystem

Le concept

Les checkpoints créent des snapshots automatiques de votre répertoire de travail avant chaque modification de fichier par l'agent. Si l'agent fait une erreur — supprime un fichier, casse un code, applique un mauvais patch — vous pouvez revenir en arrière instantanément.

L'implémentation est élégante : elle utilise des shadow git repositories. Un dépôt git invisible est maintenu en parallèle de votre répertoire de travail, sans aucun fichier .git visible dans votre projet. Chaque snapshot est un commit git dans ce dépôt shadow. Votre projet n'a pas besoin d'être un dépôt git pour que les checkpoints fonctionnent — le système fonctionne avec n'importe quel répertoire.

Activation

# Via le flag CLI (le plus simple)
hermes --checkpoints

# Ou dans config.yaml
checkpoints:
  enabled: true
  max_snapshots: 50

Les checkpoints sont désactivés par défaut. Il faut les activer explicitement car ils consomment un peu d'espace disque et de CPU pour les snapshots git.

Architecture technique

Les checkpoints sont stockés dans ~/.hermes/checkpoints/{hash}/{hash} est les 16 premiers caractères du SHA-256 du chemin absolu du répertoire de travail. Cette approche déterministe garantit que le même répertoire utilise toujours le même dépôt shadow, même après un redémarrage.

Le dépôt shadow utilise les variables d'environnement GIT_DIR + GIT_WORK_TREE pour ne pas polluer votre projet avec un dossier .git. Le dépôt shadow est strictement isolé de la configuration git de l'utilisateur — il n'hérite pas de ~/.gitconfig, des hooks, ou du GPG signing.

Exclusions automatiques : les éléments suivants ne sont pas snapshotés car ils sont soit trop volumineux, soit volatiles, soit sensibles :

  • Dépendances : node_modules/, dist/, build/, __pycache__/, .venv/, venv/
  • Variables d'environnement : .env, .env.*, .env.local, .env.*.local
  • Cache : .next/, .nuxt/, .cache/, coverage/, .pytest_cache/
  • Métadonnées : .git/, *.log, .DS_Store

Cette liste est suffisante pour la majorité des projets. Les répertoires de plus de 50 000 fichiers sont automatiquement ignorés pour éviter les ralentissements.

Déclenchement automatique

Les checkpoints sont créés automatiquement avant les opérations de modification de fichiers :

  • write_file — avant chaque écriture de fichier (création ou remplacement complet)
  • patch — avant chaque modification ciblée (find-and-replace)

Un seul checkpoint par répertoire et par tour de conversation. Si l'agent modifie 5 fichiers dans le même répertoire au cours d'un seul tour, un seul snapshot est pris avant la première modification. Ce mécanisme de déduplication évite les snapshots redondants.

Les checkpoints ne sont pas créés pour les répertoires trop sensibles :
- / (racine du filesystem)
- $HOME (répertoire personnel)

Cette protection empêche les snapshots accidentels de tout le système, qui seraient coûteux en temps et en espace disque.

La commande /rollback

La commande /rollback est votre interface pour gérer les checkpoints en session :

/rollback                 # Lister tous les checkpoints disponibles
/rollback 1               # Restaurer le checkpoint N
/rollback diff 1          # Prévisualiser les changements depuis le checkpoint 1
/rollback 1 config.yaml   # Restaurer un seul fichier depuis le checkpoint 1

Liste des checkpoints (/rollback sans argument) : affiche un tableau avec le numéro, le hash court, la date, la raison du snapshot, et les statistiques (fichiers modifiés, insertions, suppressions). Les checkpoints sont listés du plus récent au plus ancien.

Restauration complète (/rollback N) : tous les fichiers du répertoire reviennent à l'état du checkpoint N. Le dernier tour de chat est également annulé, car l'état du filesystem a changé — l'agent doit reconsidérer ses actions dans le nouveau contexte.

Restauration partielle (/rollback N fichier) : seul le fichier spécifié est restauré à partir du checkpoint N. Les autres fichiers conservent leur état actuel. Idéal quand l'agent a cassé un fichier précis sans toucher aux autres — vous restaurez juste le fichier endommagé.

Prévisualisation (/rollback diff N) : affiche les modifications apportées depuis le checkpoint N sans rien changer. Indispensable pour vérifier ce que vous allez restaurer avant de le faire.

Limite des snapshots et pruning

Par défaut, 50 snapshots maximum par répertoire. Les plus anciens sont automatiquement purgés quand la limite est atteinte. Le pruning peut aussi être déclenché manuellement.

Configurez avec checkpoints.max_snapshots dans votre config.yaml. Pour les sessions de développement longues (refactorings en plusieurs étapes), montez cette valeur à 100 ou 200.

Vérification d'intégrité

Les opérations de rollback incluent des validations de sécurité :

  • Chemin relatif obligatoire : les chemins absolus sont rejetés — seuls les chemins relatifs au répertoire de travail sont acceptés
  • Protection contre le path traversal : les tentatives comme ../../etc/passwd sont bloquées
  • Validation des hash de commit : les hash sont vérifiés (4-64 caractères hexadécimaux, ne commençant pas par -) pour prévenir l'injection de commandes git

Combiner Code Execution et Checkpoints

Le combo --checkpoints + execute_code est la configuration la plus puissante pour le développement avec Hermes :

  1. Activez les checkpoints au démarrage : hermes --checkpoints
  2. Demandez à l'agent d'effectuer des modifications complexes
  3. L'agent utilise execute_code pour orchestrer les opérations
  4. Chaque write_file dans le script déclenche un checkpoint automatique
  5. Si le résultat est incorrect : /rollback N pour revenir en arrière

C'est comme un undo/redo pour toutes les opérations de l'agent, avec la puissance d'un script Python pour les opérations complexes.

Workflow concret

hermes --checkpoints

# Dans la session :
> Refactor le module auth.py pour utiliser JWT au lieu de sessions.
  Mets à jour les 3 fichiers de tests correspondants et vérifie la syntaxe.

L'agent génère un script execute_code qui :
1. Lit auth.py et les fichiers de tests
2. Analyse la logique d'authentification existante
3. Réécrit le module avec JWT
4. Met à jour les tests
5. Vérifie la syntaxe Python de chaque fichier modifié

Chaque write_file dans le script déclenche un checkpoint. Si un test échoue :

> Lance les tests avec pytest

/rollback 3          # Revenir au checkpoint 3 (avant la réécriture des tests)
> Corrige l'erreur dans les tests JWT

Configuration recommandée pour le développement

# ~/.hermes/config.yaml
checkpoints:
  enabled: true
  max_snapshots: 100

code_execution:
  mode: project

Lancez toujours avec : hermes --checkpoints

Un VPS Hostinger avec 2 vCPU et 4 Go de RAM offre largement assez de ressources pour exécuter Hermes avec les checkpoints et le code execution, même sur des projets conséquents.

Conclusion

Code Execution et Checkpoints sont deux fonctionnalités complémentaires qui transforment Hermes Agent en un environnement de développement fiable et réversible. execute_code permet à l'agent de manipuler des données complexes en un seul tour (économisant tokens et temps), tandis que les checkpoints garantissent que chaque modification de fichier peut être annulée proprement avec /rollback.

Les points clés à retenir :

  • execute_code est déclenché automatiquement par l'agent quand une tâche nécessite 3+ appels d'outils — pas besoin de le demander explicitement
  • Le scrubbing des variables d'environnement protège vos clés API même dans les scripts Python
  • Activez --checkpoints pour tout travail impliquant des modifications de fichiers — la sécurité de pouvoir revenir en arrière n'a pas de prix
  • /rollback est votre filet de sécurité : restauration complète ou partielle, avec prévisualisation des diffs
  • Mode project pour le développement courant, mode strict pour les scripts où l'isolation est prioritaire
  • Shadow git — votre projet n'a pas besoin d'être un dépôt git, les checkpoints fonctionnent partout

Pour approfondir la sécurité autour de l'exécution de code, consultez notre article sur la sécurité et les permissions et découvrez comment le système de fichiers et le contexte interagissent avec ces mécanismes.