Hermes embarque son propre gestionnaire de paquets : ce que pm doctor, repair et gc corrigent vraiment


Un matin, hermes refuse de démarrer : un unique ModuleNotFoundError, et tout ce que vous avez fait hier, c’est installer un plugin. Ou l’inverse — la même config fonctionne sur votre laptop et prétend qu’un outil n’existe pas sur le desktop. Vous ouvrez pip list pour comprendre et vous découvrez trois environnements Python qui s’ignorent totalement.

C’est pour ça que Hermes embarque son propre gestionnaire de paquets. hermes pm ne gère pas l’application Hermes (ça, c’est hermes update) ; il gère la couche en dessous : les binaires d’outils et les environnements de dépendances Python. Une fois cette frontière claire, chaque sous-commande trouve sa place évidente.

Ce dont il a la charge

La doc le résume en trois métiers : installer des binaires d’outils épinglés et les mettre sur le PATH, préparer des environnements Python gérés pour Hermes, et expliquer la différence entre ce qui est déclaré et ce qui est réellement installé.

Chaque fichier impliqué joue un seul rôle, et les confondre est la mauvaise lecture la plus courante :

Fichier Rôle
pm/lock.json Versions exactes des outils gérés, URL par cible, hachages SHA-256
pm/pyproject.toml + pm/uv.lock Exigences Python du gestionnaire de dépendances lui-même, et son lock
pyproject.toml + uv.lock Exigences du projet principal, extras, marqueurs de plateforme
facts.json du tool-store Entrées d’outils installés, identités, exports d’environnement, empreintes des fichiers réalisés
facts.json par installation L’environnement Python choisi, son tampon d’entrée, les extras activés

Une entrée de lockfile ne prouve pas qu’un paquet est installé. Cette seule phrase explique hermes pm doctor : il compare l’état installé au lock et vérifie les octets réellement présents.

Les quatre commandes du quotidien

hermes pm status     # le dernier reçu de sync/update en JSON, ou un simple "no receipt"
hermes pm doctor     # les identités d'outils, fichiers et empreintes correspondent-ils au lock ?
hermes pm install    # outils requis + Python, puis synchronisation de l'extra all
hermes pm repair     # reconstruire et valider l'environnement de dépendances Python

status est le point de départ le moins coûteux. Il affiche le reçu le plus récent — voici une sortie réelle de cette machine, tronquée :

{
  "exit_code": 0,
  "feature_list": null,
  "finished_at": "2026-10-21T16:57:52.054592+00:00",
  "kind": "plugin-check",
  "outcome": "ok",
  "plugin_checks": [],
  "refusal": null,
  "schema": 1,
  "steps": [],
  "update_id": null,
  "venv_rebuild": null,
  "warnings": []
}

outcome, refusal, warnings et steps suffisent en général à distinguer un succès d’une exécution partielle ou d’un refus.

install mérite son propre paragraphe. Un pm install nu installe les outils requis plus Python, met les outils sur le PATH, synchronise l’extra all, et installe aussi les outils optionnels par défaut — agent-browser avec Chromium, et cua-driver. Un téléchargement raté de ces outils optionnels affiche un avertissement et ne fait pas échouer l’installation, parce que la plupart des gens veulent seulement le CLI, pas un navigateur ni le contrôle du bureau.

Si vous les avez écartés à l’installation avec --skip-browser ou --skip-computer-use, ce choix est enregistré : les installations nues suivantes et hermes update continuent de les laisser de côté. Pour revenir en arrière, nommez le paquet une fois — hermes pm install agent-browser.

Réparer une chaîne de dépendances cassée

repair et gc résolvent des problèmes différents ; les confondre fait perdre du temps.

pm repair rejoue dans une nouvelle génération l’ensemble de dépendances enregistré de la génération sélectionnée, le valide, puis le sélectionne. Point crucial : il ne lit pas la configuration des plugins, donc la config de plugin qui a cassé vos dépendances n’est pas relue. Il ne touche pas non plus aux épinglages, aux extras ni à la config des plugins. Si l’enregistrement est illisible ou si le lock sauvegardé manque, il échoue plutôt que de vous tendre un environnement amoindri.

Au démarrage, Hermes demande la même réparation quand il trouve des dépendances incomplètes, mais les tentatives automatiques sont bornées ; lancer pm repair explicitement ne l’est pas.

pm gc supprime ce que plus rien ne référence : entrées orphelines du tool-store, téléchargements partiels éligibles, environnements Python gérés par bail devenus inutilisés, et l’état installs/INSTALL_KEY/ des checkouts qui n’existent plus. Il est volontairement prudent — il conserve les checkouts que ce processus ne voit pas (une installation hôte vue depuis un conteneur partageant la racine de données, par exemple) et tout état dont le verrou d’installation ou le bail d’environnement est encore tenu.

Moyen mnémotechnique en une ligne : cassé, c’est repair ; gonflé, c’est gc.

Épinglages, la règle des trois jours et les miroirs

Chaque paquet Python dont Hermes dépend directement doit avoir au moins trois jours au moment où Hermes le verrouille — le exclude-newer de uv, appliqué par la vérification de lock en CI. L’intention est simple : un paquet publié il y a quelques minutes, éventuellement compromis, ne peut pas atteindre uv.lock.

Conséquence pratique : hermes pm lock est l’étape qui applique ce contrôle, et face à un miroir qui ne publie pas d’heures de dépôt il s’arrête sur has no publish time. Quand vous voyez ça, pointez cette étape-là vers https://pypi.org/simple ; les installations du quotidien peuvent continuer de passer par le miroir.

Les miroirs se configurent avec index-url dans pip.conf, que Hermes transmet à uv, ou avec UV_INDEX_URL.

Les téléchargements sont retentés, pas les mauvais hachages

La politique de retry vaut la peine d’être mémorisée :

  • Au plus quatre tentatives par sonde ou transfert, avec un back-off de 1, 2 et 4 secondes ; un en-tête Retry-After peut allonger l’attente jusqu’à 30 secondes.
  • Retentés : 408, 429, 500, 502, 503, 504, plus les réinitialisations de connexion, les timeouts, les échecs DNS temporaires et les corps de réponse interrompus.
  • Les téléchargements par plage conservent les octets déjà reçus ; les serveurs sans support des plages exigent un flux neuf.
  • Pas retentés : les hachages non concordants, les échecs de certificat, les erreurs locales du système de fichiers — des échecs définitifs.

Donc si un téléchargement échoue trois fois, lisez la cause dans le log avant d’accuser le réseau.

Commandes de mainteneur, et le nouveau drapeau

Ce sont des outils de développement et de packaging ; la plupart des utilisateurs n’en ont jamais besoin.

Commande Effet
pm lock Recalculer uv.lock depuis pyproject.toml ; n’écrit rien si le lock est à jour
pm lock --bump NAME VERSION Résoudre et hacher les artefacts cibles, puis écrire l’épinglage dans pm/lock.json
pm update [names...] Interroger les versions amont, changer les épinglages, installer les outils modifiés
pm update --check Interroger sans écrire ; un code de sortie 1 peut signifier des mises à jour disponibles — lisez la sortie
pm update --target TARGET Résoudre les versions pour une cible donnée
pm update --uv / --npm Rafraîchir aussi la résolution Python ou npm
pm update --termux [--check] Réépingler les archives du pool termux que le pool roulant a retirées
pm bundle --out DIR Préparer une charge portable (snapshot des sources, outils, dépendances) — pas un installeur signé

Le nouveau pm update --skip-target TARGET règle une contrariété précise : quand l’amont traîne, vous ne voulez pas que les épinglages d’une cible donnée soient rafraîchis. Disons que le pool termux est encore en train de rattraper son retard et que vous voulez qu’une passe de mise à jour laisse linux-arm64-bionic tranquille — passez le drapeau (répétable) et ces épinglages restent tels quels, tandis que les exécutions suivantes continuent de considérer le paquet comme à jour.

Dépannage par symptôme

  • Un outil manque ou n’est pas à la bonne version → lisez pm doctor, puis pm install explicitement ce paquet sur une installation inscriptible.
  • Conflit de dépendances → lisez pm status, corrigez les exigences déclarées par le plugin, réessayez.
  • Dépendances Python endommagées → pm repair, puis redémarrez Hermes.
  • Un nouvel environnement n’a pas pris effet → redémarrez le processus Hermes concerné. N’ajoutez pas un second arbre site-packages à un chemin d’import vivant.
  • Disque mangé par de vieux environnements → pm gc ; si le disque est déjà plein, notre guide d’élagage automatique en cas de disque bas couvre le côté runtime.
  • Paquet ou extra inconnu → pm install attend des noms de paquets, pas des noms d’extras Python ni des spécifications pip name==version.

Le parti pris de conception

hermes pm est construit pour échouer bruyamment au lieu de vous tendre discrètement un environnement dégradé. Un tableau de coûts mal formé empêche un serveur de se charger, un enregistrement illisible fait échouer repair, un pool termux retiré fait sortir une mise à jour en erreur — tout ça pour que le problème remonte maintenant plutôt que sous la forme d’une panne étrange la semaine prochaine.

Si tout ce que vous voulez est de mettre à jour Hermes lui-même, vous n’aurez jamais besoin de pm ; le guide de mise à jour en douceur couvre cet autre chemin.