Hermes Agent sur Mac : setup local-first avec deux profils, A (local) et B (cloud)
Pour qui ? Utilisateurs macOS Apple Silicon qui veulent un assistant IA local-first souverain pour leurs données sensibles, ET un mode cloud haute performance pour les tâches qui le justifient. Public technique à l’aise avec le terminal, qui n’a pas peur d’éditer un
config.yaml.
TL;DR
| Mode A (local) | Mode B (cloud) | |
|---|---|---|
| Modèle | gpt-oss:20b (Ollama, daily driver) ; override gemma4:26b | MiniMax-M3 (minimax-oauth) plus une chaîne de fallback |
| Réseau | Aucun. Strictement local. | Cloud (Claude, Gemini, Nous, OpenRouter) |
| Données sensibles | Oui | Jamais |
| Toolset | Léger (6 outils, ~83 KB prompt) | Complet |
| Performance | ~40 s première réponse (gpt-oss), ~80 s (gemma4:26b) | <5 s (cloud) |
| Bascule | ops/hermes-mode.sh a | ops/hermes-mode.sh b |
Trois principes du setup :
- Code dans
~/DEV/hermes-agent(versionné Git), secrets dans~/.hermes(hors repo) - Deux profils Hermes natifs :
default(local) etcloud, chacun avec sonHERMES_HOMEisolé - Un répertoire de travail dédié (
~/DEV/hermes-work/) avec son propreAGENTS.md, pas lancé depuis le repo
Partie 1 : installation
Pourquoi deux profils et pas un seul ?
Avant de me lancer, j’ai hésité : un seul profil avec hermes chat -m <model>
pour switcher de modèle à la volée, c’est tentant. En creusant, j’ai compris
que les profils Hermes ne servent pas qu’à choisir un modèle. Chaque profil
est un HERMES_HOME complètement isolé :
config.yaml,.env, mémoire, sessions, sandbox, skills : tout est dupliqué- l’
AGENTS.mddu cwd est lu séparément - les outils peuvent diverger entre profils
Conséquences concrètes :
- Isolation des secrets : si une injection de prompt lit le
.enven Mode A, elle ne trouve aucun token Claude/Gemini/OpenRouter - Posture par défaut safe : Mode A est l’actif au démarrage, je dois basculer explicitement pour sortir
- Isolation des sandbox : mon travail cloud ne pollue pas mes fichiers locaux
- Toolsets divergents : Mode A peut être allégé pour la perf sans toucher au Mode B
C’est documenté côté Nous Research, et c’est un choix de design : « profiles are
independent islands on purpose » (cf. l’AGENTS.md du repo, ligne 138).
Pourquoi code et secrets séparés ?
~/DEV/hermes-agent est un repo Git (celui de Nous Research, forkable). Si j’y
mets mes clés API, git status les affiche et un git add maladroit les
commit. Solution : tout ce qui est secret ou partagé vit dans ~/.hermes/,
jamais dans le repo. C’est la convention que suit le bootstrap officiel.
Pré-requis
- macOS Apple Silicon (testé sur M2 Max)
- Docker Desktop lancé (icône active dans la barre de menus) : le backend d’exécution sandbox
- Ollama installé (
brew install ollama) - un terminal
zsh
docker info # doit afficher les server info, pas une erreur de connexion
ollama --version
Build et install
# Build tools
curl -LsSf https://astral.sh/uv/install.sh | sh
brew install node
exec $SHELL -l
# Clone (submodules = plugins/skills tiers)
mkdir -p ~/DEV
git clone --recurse-submodules https://github.com/NousResearch/hermes-agent.git ~/DEV/hermes-agent
cd ~/DEV/hermes-agent
# venv + editable install (Python 3.11 pinned)
uv venv venv --python 3.11
export VIRTUAL_ENV="$(pwd)/venv"
uv pip install -e ".[all,dev]"
# Navigateur local (utilisé par certains outils en Mode A)
npm install
npx playwright install chromium
# Expose le launcher venv (PAS le wrapper du repo)
mkdir -p ~/.local/bin
ln -sf "$(pwd)/venv/bin/hermes" ~/.local/bin/hermes
grep -q 'HOME/.local/bin' ~/.zshrc || echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
exec $SHELL -l
hermes version # vérifie l'install
Configuration initiale
hermes setup # wizard interactif
hermes doctor # health check complet
Clés et identités : où vit quoi
Mode A, ~/.hermes/.env (la posture souveraine réelle, gardée clean) :
TAVILY_API_KEY=tvly-xxxx # recherche web
FIRECRAWL_API_KEY=fc-xxxx # extraction de page
GITHUB_TOKEN=ghp_xxxx # rate limit Skills Hub (optionnel)
TELEGRAM_BOT_TOKEN=... # OK : canal chat, pas auth modèle
TELEGRAM_ALLOWED_USERS=...
TELEGRAM_HOME_CHANNEL=...
TERMINAL_ENV=docker
# Volontairement absent : OPENROUTER_API_KEY, EXA_API_KEY, GOOGLE_API_KEY,
# ANTHROPIC_TOKEN. Toutes les clés cloud vivent dans profiles/cloud/.env.
Mode B, ~/.hermes/profiles/cloud/.env (et/ou via login OAuth) :
| Provider | Auth | Commande |
|---|---|---|
| MiniMax-M3 (primary actuel) | OAuth (minimax-oauth) | hermes -p cloud model |
| Claude (Anthropic) | OAuth (Claude Pro) | hermes -p cloud model puis Anthropic puis login navigateur |
| Google Gemini | clé API (GEMINI_API_KEY) | Choix volontaire : Google déconseille l’OAuth Gemini dans un agent tiers |
| Nous Portal | OAuth | hermes login |
| OpenRouter | clé API | Filet de secours large |
Note ToS : utiliser un abonnement Claude Pro via OAuth dans un agent tiers est une zone grise. Ça fonctionne, mais la voie officielle reste la clé API Anthropic (comme pour Google Gemini).
Backend d’exécution : Docker
hermes setup tools # Execution / Terminal backend puis docker
hermes config set terminal.backend docker # verify
L’image par défaut est nikolaik/python-nodejs:python3.11-nodejs20. Les
sandbox persistent leurs fichiers dans ~/.hermes/sandboxes/<profile>/.
Modèles : choisir pour chaque usage
Mode A : deux modèles pour deux usages
| Modèle | Taille | Temps 1re réponse | Usage |
|---|---|---|---|
gpt-oss:20b | 13 GB | ~40 s | Daily driver : Excel, CSV, transformations, debug |
gemma4:26b-a4b-it-q4_K_M | 17 GB | ~80 s | Veille sensible, raisonnement long |
Pourquoi deux modèles ? Au début je tournais uniquement sur le 26B Gemma. Problème : sur un M2 Max, un forward pass à travers 26B de paramètres sature le compute avant que la taille du prompt ne compte. Mesures : toolset complet vs toolset léger = 1m vs 1m20s, dans la marge d’erreur. Le vrai levier de vitesse locale, c’est la taille du modèle.
Setup :
# Vérifier ce qui est installé
ollama list
# Puller ce qui manque (gpt-oss:20b fait 13 GB, gemma4:26b fait 17 GB)
ollama pull gpt-oss:20b
ollama pull gemma4:26b-a4b-it-q4_K_M
# Mettre gpt-oss:20b comme primary du Mode A
hermes -p default model # picker interactif
# Override ponctuel vers le 26B (veille sensible) :
hermes -p default chat -m gemma4:26b-a4b-it-q4_K_M
Piège context window : Hermes Agent exige au moins 64K tokens de contexte. Plusieurs modèles 7B (comme
qwen2.5-coder:7b) plafonnent à 32K et sont refusés à l’init. Toujours vérifier avant d’adopter un modèle :ollama show <model>ouollama run <model> /show info.
Mode B : primary plus chaîne de fallback
Primary actuel : MiniMax-M3 (provider minimax-oauth, base
https://api.minimax.io/anthropic). Chaîne de fallback ordonnée :
Primary: MiniMax-M3 (via minimax-oauth)
1. claude-opus-4-8 (via anthropic, OAuth Claude Pro ou clé API)
2. gemini-3.5-flash (via gemini, clé API Google)
3. stepfun/step-3.7-flash:free (via nous)
4. openai/gpt-5.5 (via openrouter, clé API)
L’ordre se gère via :
hermes -p cloud fallback list # inspecter
hermes -p cloud fallback add # ajouter une entrée (picker validé)
hermes -p cloud fallback remove # retirer une entrée
hermes -p cloud fallback clear # repartir de zéro
Certains me demandent pourquoi MiniMax-M3 plutôt que Claude Opus 4.8. Le coût, déjà, sans commune mesure. Et puis le contexte géostratégique : je suis français, je vis en Europe, et je vois bien que ça pue d’avoir tous nos œufs dans le même panier.
Setup des deux profils
Le wrapper ops/hermes-mode.sh est fourni par le repo et simplifie la bascule.
Pour le Mode B :
# One-time : crée le profil 'cloud' isolé
ops/hermes-mode.sh bootstrap
# Logins cloud (one-time, interactif)
hermes -p cloud model # MiniMax-M3 primary, puis Claude OAuth si besoin
# Mettre les clés API dans ~/.hermes/profiles/cloud/.env :
# GEMINI_API_KEY=...
# OPENROUTER_API_KEY=...
# Chaîne de fallback
hermes -p cloud fallback clear
hermes -p cloud fallback add # Gemini, puis Nous, puis OpenRouter
hermes -p cloud fallback list
Partie 2 : usage quotidien
Le piège : ne JAMAIS lancer hermes chat depuis le repo
Si tu fais cd ~/DEV/hermes-agent && hermes chat, l’AGENTS.md du repo (69 KB,
un guide de dev pour contributeurs Hermes) est auto-injecté puis tronqué à
~31 KB. Résultat : un warning systématique,
Context file AGENTS.md TRUNCATED: 69356 chars exceeds limit of 31457, et tu
bouffes du prompt, donc des tokens, pour rien.
Solution : crée un répertoire de travail dédié.
mkdir -p ~/DEV/hermes-work
Mets-y un AGENTS.md qui te ressemble : généraliste, 1 à 2 KB, avec ton style
de travail et tes contraintes. Exemple de contenu :
# Contexte utilisateur
Tu es mon assistant IA personnel. Tu m'aides dans mes tâches quotidiennes
(analyse de données, veille, scripting, debug, rédaction, etc.).
## Posture par défaut
- Mode local (par défaut) : Ollama via Hermes, aucun appel réseau.
- Mode cloud : uniquement sur demande explicite.
## Style de travail
- Va droit au but. Pas de préambule, pas de reformulation.
- Réponds en français sauf si la tâche est en anglais.
- Pour le code : snippets concrets et exécutables.
- Si tu ne sais pas, dis-le.
## Sécurité et données
- Pas de commande destructive sans validation.
- Pas d'upload hors du Mac sans demande explicite.
- Pour les fichiers sensibles : traitement local (pandas/openpyxl).
## Mémoire et contexte
- Pour un travail récurrent, propose un nom de projet pour `hermes sessions --continue`.
Personnalise-le au fil du temps (préférences, contraintes métier). C’est ton briefing de contexte par répertoire.
Toolset léger pour Mode A
Par défaut, le profil default charge le toolset complet (hermes-cli, ~100
outils, ~250 KB de schemas). Pour le Mode A, on allège.
Dans ~/.hermes/config.yaml :
platform_toolsets:
cli: [file, memory, session_search, terminal, todo, web]
telegram: [file, memory, session_search, terminal, todo, web]
Effet mesuré : toolset léger = 31 outils, ~83 KB de prompt (vs ~250 KB). Le gain de vitesse est marginal sur le 26B (compute-bound), mais sensible sur gpt-oss:20b. Le vrai bénéfice est ailleurs : surface d’attaque réduite, logs plus lisibles.
Pour tout réactiver ponctuellement : cli: [hermes-cli], ou bascule en Mode B.
Workflow quotidien
# Une session de travail local
cd ~/DEV/hermes-work
ops/hermes-mode.sh a # Mode A (local/privé)
hermes chat # ouvre la session
# Une session de travail cloud
cd ~/DEV/hermes-work
ops/hermes-mode.sh b # Mode B (cloud)
hermes chat
# Overrides ponctuels (sans toucher au profil actif)
hermes chat -m gemma4:26b-a4b-it-q4_K_M # autre modèle, même profil
hermes chat -p cloud # une session Cloud sans basculer
hermes chat -p cloud -m claude-opus-4-8 # Cloud + modèle spécifique
hermes chat -t terminal,file,memory # toolset ad hoc
Le profil actif est persistant
Une fois ops/hermes-mode.sh a (ou b) exécuté, tous tes hermes suivants
héritent du choix, y compris après fermeture du terminal. La seule source de
vérité est ~/.hermes/active_profile. Pour vérifier :
ops/hermes-mode.sh status
hermes profile
Bot Telegram
Le bot Telegram est un daemon séparé, installé comme service launchd.
Setup initial :
# Mode A par défaut
ops/hermes-mode.sh a
hermes gateway install # daemon + auto-start au login
hermes gateway start # démarre maintenant
hermes gateway status # vérifie : "running"
Après chaque bascule A/B, redémarre le gateway pour qu’il recharge la config (sinon il continue à servir avec l’ancien profil) :
ops/hermes-mode.sh b
hermes gateway restart
Côté mobile : aucun réglage à faire. Envoie un message à ton bot, il répond avec le modèle du profil actif.
Commandes utiles :
| Action | Commande |
|---|---|
| Voir l’état du gateway | hermes gateway status |
| Stopper le bot | hermes gateway stop |
| Redémarrer après bascule | hermes gateway restart |
| Logs | hermes logs gateway |
Tableau résumé
| Tu veux… | Tu fais… |
|---|---|
| Travailler en local | cd ~/DEV/hermes-work && ops/hermes-mode.sh a && hermes chat |
| Travailler en cloud | cd ~/DEV/hermes-work && ops/hermes-mode.sh b && hermes chat |
| Une seule session cloud | hermes -p cloud chat (profil actif inchangé) |
| Changer de modèle | hermes chat -m <model-id> |
| Voir l’état | ops/hermes-mode.sh status |
| Bascule + bot Telegram | ops/hermes-mode.sh b && hermes gateway restart |
| Stopper le bot | hermes gateway stop |
Mise à jour
Une seule commande :
hermes update
Elle met à jour le repo, les deps Python et les submodules. Inutile de refaire
un git pull à la main.
Où sont stockées mes données ?
| Quoi | Où |
|---|---|
| Code Hermes | ~/DEV/hermes-agent |
| Config + secrets Mode A | ~/.hermes/ |
| Config + secrets Mode B | ~/.hermes/profiles/cloud/ |
| Sandbox Mode A (bind Docker) | ~/.hermes/sandboxes/ |
| Sandbox Mode B (bind Docker) | ~/.hermes/profiles/cloud/sandboxes/ |
| Sessions, memory, skills | Dans chaque profil (~/.hermes/<profile>/...) |
L’image Docker utilisée est nikolaik/python-nodejs:python3.11-nodejs20. Le
home /root du container est mappé en bind vers le sandbox dir ci-dessus, donc
il persiste entre les sessions.
Validation périodique
ops/hermes-mode.sh status
hermes doctor # Mode A
hermes -p cloud doctor # Mode B
hermes -p cloud fallback list # chaîne de fallback Mode B
hermes prompt-size # Mode A : 31 outils, ~83 KB prompt total
Partie 3 : pour aller plus loin
Use cases documentés
- Daily Briefing Bot : résumer ta veille du matin https://hermes-agent.nousresearch.com/docs/guides/daily-briefing-bot
- Team Assistant Telegram : un assistant d’équipe via Telegram https://hermes-agent.nousresearch.com/docs/guides/team-telegram-assistant
- Python Library : utiliser Hermes comme librairie Python dans ton code https://hermes-agent.nousresearch.com/docs/guides/python-library
- MCP avec Hermes : si vraiment nécessaire https://hermes-agent.nousresearch.com/docs/guides/use-mcp-with-hermes
- Plus d’usages : https://hermes-agent.nousresearch.com/docs/user-stories
Tips officiels
https://hermes-agent.nousresearch.com/docs/guides/tips
Et si la CLI te fatigue : Hermes Desktop
Une fois que tout ça tourne et que c’est pleinement opérationnel, si la CLI
finit par te fatiguer et qu’une petite GUI à la Claude Desktop ou Minimax Code
te manque, tu peux lancer hermes desktop et voilà. Même config, mêmes profils,
mêmes secrets isolés : juste une interface graphique par-dessus.
https://hermes-agent.nousresearch.com/docs/user-guide/desktop
Leçons de ce setup
- Les profils Hermes sont une frontière de sécurité, pas un choix de modèle. Isolation des secrets, des sandbox, des sessions, posture par défaut safe.
- Le bottleneck de perf en local, c’est le compute (taille du modèle), pas le prompt. Réduire le toolset de 100 à 6 outils ne change presque rien au chrono. Le levier de vitesse, c’est le modèle.
- Toujours vérifier le context window avant d’adopter un modèle. Hermes exige au moins 64K. Les modèles 7B plafonnent souvent à 32K.
- Ne JAMAIS lancer
hermes chatdepuis le repo du framework. L’AGENTS.mddu repo (69 KB) est injecté et tronqué. Crée un répertoire de travail avec ton propre AGENTS.md. - Un
.envMode A clean, c’est la posture souveraine réelle. Toute clé cloud dans~/.hermes/.envest un canal de fuite en cas d’injection de prompt.
Conclusion
Ce setup tourne en production perso depuis quelques semaines. Mode A pour toute
la donnée sensible (Excel de compta, CSV clients, configs, RGPD inside), Mode B
pour la veille publique et les tâches qui demandent un gros modèle. Le wrapper
ops/hermes-mode.sh rend la bascule transparente. Le bot Telegram donne accès
au même agent depuis mon mobile.
Le coût en complexité est celui du setup initial. Au quotidien, c’est juste
cd ~/DEV/hermes-work && ops/hermes-mode.sh a && hermes chat.
Note : ce document est une note personnelle restructurée pour publication. Tout retour est bienvenu.