Commit Graph
980 Commits
Author SHA1 Message Date
Hermes Agent bfd1a3c865 fix(hermes): pointer hermes_api_server_env sur la clé réelle du secret (hermes_discord_bridge_env)
Le fichier secrets/discord-hermes-bridge.yml n'a pas (encore) été rekeyé côté
sops (hermes ne peut pas déchiffrer/réécrire un secret existant : pas de clé
age privée). Utilise key= pour lire la clé qui existe réellement, TODO pour
marc de renommer proprement plus tard.

Trouvé en testant le build réel (nixos-rebuild build) : sops-install-secrets
échouait avec 'the key hermes_api_server_env cannot be found'.
2026-09-27 21:27:18 -04:00
Hermes Agent a2e20bc376 chore(secrets): rotation admin_password gitea 2026-09-27 21:24:55 -04:00
Hermes Agent 97fe5aa462 chore(secrets): secret hermes-discord.yml (token bot Discord natif hermes) 2026-09-27 21:24:55 -04:00
Hermes Agent 40f0b407a8 feat(hermes): plugin desktop vim-bindings (déclaratif, désactivé)
tmpfiles crée le dossier /var/lib/hermes/.hermes/desktop-plugins/vim-bindings ;
le service qui l'active est commenté (heredoc JS mal géré par nix pour le moment).
2026-09-27 21:24:44 -04:00
Hermes Agent 3ab98797af feat(hermes): connexion mcpServers.gitea (gitea-mcp) + note vaultwarden désactivé 2026-09-27 21:24:27 -04:00
Hermes Agent 5b181bd840 refactor(hermes): API server OpenAI-compatible unifié, retrait du gateway discord-bridge dédié
Un seul listener par hôte (profil default) sert tous les profils sous
/p/<profil>/... au lieu d'un gateway séparé par profil. Le pont Discord
existant (services/discord-bot) appelle maintenant
http://127.0.0.1:8642/p/discord-bridge/v1/chat/completions et expose une
surface de test locale (HERMES_BRIDGE_ASK_PORT). services/discord-hermes-bridge
(gateway dédié, 71 lignes) est retiré ; la clé est réutilisée depuis
secrets/discord-hermes-bridge.yml (clé renommée hermes_api_server_env).
2026-09-27 21:23:34 -04:00
Hermes Agent af4ed70b6b feat(hermes): bot Discord natif dédié (voix + texte, profil discord-bridge)
- enableDiscordToken (option, même contrainte que enableMatrixToken : tower only)
- DISCORD_ALLOWED_USERS (@marc uniquement)
- plugin discord-auto-join : rejoint automatiquement le vocal quand un membre
  autorisé y entre (register_platform_handler + join_voice_channel)
- Opus (libopus) : LD_LIBRARY_PATH posé sur l'unité systemd dès le démarrage
  (dlopen lit sa valeur au lancement, pas via .env) ; binutils (ld/objdump)
  pour le repli find_library, ffmpeg pour la conversion PCM 48kHz TTS/réception
- secret hermes_discord_env (secrets/hermes-discord.yml)
2026-09-27 21:23:10 -04:00
Hermes Agent 3b6b531102 revert(home-manager): retour au profil standalone, herdr posé côté système
home-manager.useGlobalPkgs=true (test perf, évite d'évaluer nixpkgs 2x) est
revenu trop cher/instable en pratique. Retour à home-manager.users.marc
totalement désactivé côté système (profil standalone via `HM=marc just home`
uniquement). Conséquences :
- modules/home/gtk : catppuccin.autoEnable repasse à sa valeur par défaut
- modules/home/zen-browser : l'overlay nur revient dans son propre module
- profiles/common : commentaire nettoyé (n'a plus besoin d'expliquer le piège
  useGlobalPkgs, qui ne s'applique plus)
- herdr : posé côté système (modules/nixos/herdr, symlink store ->
  ~/.config/herdr/config.toml) puisque le home-manager systeme ne construit
  plus la conf de marc ; modules/home/herdr et son import dans
  users/marc/home.nix restent (profil standalone), mais ne sont plus le
  mécanisme actif sur tower.
2026-09-27 21:21:00 -04:00
Hermes Agent 3d0a16c93a feat(hermes): activer enableDiscordToken sur tower 2026-09-27 21:20:49 -04:00
Hermes Agent 20ca7263ea chore(services): activer gitea-mcp et ibkr-mcp ; marquer stalwart-mcp/vaultwarden-mcp WIP
gitea-mcp et ibkr-mcp sont fonctionnels et importés. stalwart-mcp (cargoHash à
corriger) et vaultwarden-mcp (input flake manquant) restent commentés.
2026-09-27 21:20:32 -04:00
Hermes Agent 327b66a21f chore(services): activer radarr, media, audiobookshelf, arr-mcp
radarr était commenté depuis une régression antérieure ; media/audiobookshelf/
arr-mcp sont les modules ajoutés dans les commits précédents.
2026-09-27 21:20:22 -04:00
Hermes Agent 667a072937 feat(media): migrer la bibliothèque partagée vers /srv/media (dataset ZFS dédié)
/home/marc/media posait deux problèmes : /home/marc est 0700 (chaque service
devait recevoir un droit de traversée) et systemd-tmpfiles refuse de créer
quoi que ce soit sous /home/marc (« unsafe path transition », exit 73).

- services/media (nouveau) : dataset nixos/media -> /srv/media, groupe media
  (setgid, dossiers 2775/2770), arborescence movies/tvshows/music/books/downloads
- disko.nix : dataset media à côté de marc/nix
- navidrome, jellyfin, kodi : bibliothèque -> /srv/media/{music,movies,tvshows}
- qbittorrent : téléchargements dans le même dataset que la bibliothèque
  (permet aux *arr d'importer par lien dur au lieu de copier)
- radarr : dataDir corrigé (pointait sur celui de sonarr par copier-coller),
  déplacé hors /home (impossible avec ProtectHome+tmpfiles du module)
- sonarr : dataDir dédié + migration depuis /home/marc/radarr (était figé
  depuis le 28/07, port 8006 muet) ; réparé le 27/09/2026
- readarr : bibliothèque -> /srv/media/books
2026-09-27 21:19:52 -04:00
Hermes Agent 138a6a2a3e docs: README décrivant les machines couvertes par le flake 2026-09-27 21:19:40 -04:00
Hermes Agent 0c6e1e833d fix(hermes-webui): le watchdog title-adoption ne doit pas empêcher le démarrage
core_title_adoption.start() peut lever une exception ; elle est maintenant
attrapée et loggée en warning au lieu de crasher le serveur au boot.
2026-09-27 21:19:36 -04:00
Hermes Agent d234f5f93f feat(arr-mcp): conteneur MCP couvrant Radarr/Sonarr/Jellyfin/Prowlarr/Bazarr
ghcr.io/bardesss/arr-mcp, transport HTTP loopback (port 6060). Config (URL +
clé API de chaque service) à faire dans l'interface web du conteneur.
2026-09-27 21:19:36 -04:00
Hermes Agent 819a34629f feat(audiobookshelf): serveur de livres audio et podcasts
Bibliothèque sous /srv/media (dataset partagé, cf services/media). Clé API
dans secrets/audiobookshelf.yml, pas encore consommée par un service. Exposé
publiquement via Pangolin (audiobookshelf.marcpartensky.com).
2026-09-27 21:19:35 -04:00
Hermes Agent 78c257a2a6 feat(ibkr-mcp): serveur MCP lecture seule Interactive Brokers (Flex Web Service)
Positions, soldes, NAV, transactions via Flex Web Service (HTTPS, sans session
IBKR, sans 2FA, sans gateway local). Le token Flex est indépendant du mot de
passe du compte et révocable depuis le portail : aucun pouvoir de passer un
ordre. Token + Query IDs encore des placeholders dans secrets/ibkr.yml.
2026-09-27 21:19:35 -04:00
Hermes Agent 01589109ab feat(vaultwarden-mcp): serveur MCP Vaultwarden (binaire téléchargé, désactivé en attendant l'input flake)
jr2804/vaultwarden-mcp, binaire Rust téléchargé depuis GitHub releases (plus
simple qu'un crate2nix). Mot de passe master dans secrets/tower.yml
(vaultwarden_mcp_password). Non importé (services/default.nix) : input flake
manquant, cf FIXME.
2026-09-27 21:19:35 -04:00
Hermes Agent 9d99233987 feat(gitea-mcp): serveur MCP Gitea officiel (gitea.com/gitea/gitea-mcp v1.6.0)
- buildGoModule, transport stdio, GITEA_ACCESS_TOKEN_FILE (secret jamais en clair)
- v1.6.0 (pas la dernière) : v1.7.0 exige go >= 1.27, non fourni par nixpkgs 26.05
- secret PAT dans secrets/gitea-mcp.yml (sops)
2026-09-27 21:19:20 -04:00
Hermes Agent cb365bdb2f feat(codeberg-mcp): token via sops template (plus de placeholder en clair)
Le token Codeberg (CODEBERG_ACCOUNTS) est désormais injecté via un .env généré
par sops.templates et sourcé par le wrapper, au lieu d'un placeholder en dur
dans l'option env= (visible dans le nix store).
2026-09-27 21:19:20 -04:00
Hermes Agent fb4afea17f feat(gitea): OIDC Zitadel pour l'authentification (auto-discover, registration externe uniquement)
- services.gitea.openid : ENABLE_OPENID_SIGNIN/SIGNUP, whitelist auth.marcpartensky.com
- service oneshot gitea-oidc-init : enregistre la source OAuth2 zitadel (idempotent)
- registration classique désactivée (ALLOW_ONLY_EXTERNAL_REGISTRATION)
- secret client OIDC dans secrets/gitea-oidc.yml (sops)
2026-09-27 21:18:46 -04:00
Hermes Agent 1f6a97c8b8 fix(stalwart): expose le secret ACME via /etc plutôt que credentials systemd
LoadCredential (%{file:/run/credentials/stalwart.service/acme-secret}%) ne
fonctionnait pas de façon fiable ; le secret est maintenant écrit dans
/etc/stalwart/acme-secret (environment.etc) et référencé par ce chemin.
2026-09-27 21:18:38 -04:00
Hermes Agent 4872cc27a9 feat(stalwart-mcp): serveur MCP Rust JMAP pour Stalwart Mail (désactivé, cargoHash à corriger)
- flake input stalwart-mcp (webpatser/stalwart-mcp, pin sur commit main)
- services/stalwart-mcp : buildRustPackage, config JMAP compte marc@marcpartensky.com
- non importé (services/default.nix) : cargoHash mismatch à corriger avant activation
2026-09-27 21:18:38 -04:00
Hermes Agent 6f7be6d701 feat(gotify): OIDC Zitadel et exposition Pangolin
Gotify 3.1.0 (paquet unstable, absent de 26.05) avec SSO OIDC Zitadel en
client public (PKCE, pas de secret) et ressource Pangolin
gotify.marcpartensky.com en SSO. Le module n'est pas encore importé dans
services/default.nix (ligne ./gotify toujours commentée).
2026-09-27 17:20:31 -04:00
Hermes Agent d27aa1927e feat(hermes-webui): WebUI sur hermes.marcpartensky.com
Le WebUI est l'interface principale, il prend donc le domaine court
hermes.marcpartensky.com (full-domain Pangolin + HERMES_WEBUI_ALLOWED_ORIGINS) ;
hermes-mobile.marcpartensky.com reste réservé à l'appli mobile.
2026-09-27 17:20:31 -04:00
Hermes Agent 5cc83416d0 feat(hermes-pocket): backend du profil pocket pour l'appli mobile
hermes serve --isolated sur le profil pocket (127.0.0.1:9119) derrière un
nginx loopback qui réécrit le Host (le serveur refuse tout Host non loopback),
exposé par Pangolin sur hermes-mobile.marcpartensky.com sans SSO : l'appli
native ne peut pas faire le flux navigateur, seul le token de session du profil
protège l'accès. Les deux ports restent fermés au firewall (assertions).
2026-09-27 17:20:31 -04:00
Hermes Agent 8ea0630bec feat(hermes): nemotron 3 ultra gratuit (high) par défaut
Politique marc du 27/09/2026 : nvidia/nemotron-3-ultra-550b-a55b:free en
high par défaut, puis inkling:free, puis DeepSeek V4.1 Flash en dernier
recours. Nemotron sort de la chaîne de secours puisqu'il devient primaire.
2026-09-27 17:20:30 -04:00
Hermes Agent 8484f09b36 fix(hermes): python3 systeme pour le probe SSH de Hermes Desktop 2026-09-27 16:02:28 -04:00
Hermes Agent 05d83955eb feat(hermes-webui): titre de session repris du moteur Hermes (patch local)
Le WebUI n'écrit le titre d'une session qu'à la fin d'un run (jamais si le run
est interrompu) : la sidebar affiche le premier message brut pendant tout le run.
Le moteur Hermes (hermes_state) connaît déjà le bon titre quelques secondes après
le premier message.

default.nix patche donc le paquet amont pour y installer core_title_adoption.py
(watchdog qui recopie ce titre dans le sidecar du WebUI, state.db ouvert en
lecture seule, désactivable par HERMES_WEBUI_CORE_TITLE_ADOPTION=0) et
api_init.py. À retirer quand le comportement existera en amont dans l'input.
2026-09-27 13:01:21 -04:00
Hermes Agent 88b09f08c8 chore(tailscale): désactiver l'import dans profiles/anywhere
Le service exige le secret sops tailscale/auth_key, absent de
secrets/anywhere.yml : l'éval échouait. À réactiver avec le mesh (headscale est
utilisé en attendant).
2026-09-27 13:00:56 -04:00
Hermes Agent 2fb2975b84 fix(stalwart): stateVersion 26.05 (données live dans /var/lib/stalwart/db)
Ce stateVersion sélectionne user/group/dataDir du module, pas la release système.
Vérifié le 27/09/2026 sur le VPS (fds ouverts du process + toml actif) : les
données vivantes sont dans /var/lib/stalwart/db ; celles de /var/lib/stalwart-mail
datent de juillet 2026. Ne pas redescendre sous 26.05.
2026-09-27 13:00:56 -04:00
Hermes Agent ada0fa88e3 fix(newt): proxy-resources/protocol, attendu par le Pangolin du VPS
Le Pangolin de ce VPS (schéma ancien) ignore silencieusement public-resources et
mode : la ressource noVNC n'était jamais créée et Traefik répondait 404 sur
vnc.marcpartensky.com. Vérifié le 26/09/2026.
2026-09-27 13:00:56 -04:00
Hermes Agent c7a4a6b862 fix(protonmail-mcp): import limité à tower (éval de laptop cassée)
L'option services.protonmail-mcp vient du input protonmail-mcp, importé par le
seul profile tower : l'import global dans services/default.nix cassait l'éval de
laptop/laptop-iso (option inexistante). L'import est commenté avec la raison, et
flake.nix ajoute ./services/protonmail-mcp aux modules de tower uniquement.
2026-09-27 13:00:56 -04:00
Hermes Agent ce6235d8f2 feat(vms): VM de dev microvm.nix (just vm, nix run .#dev)
vms/dev.nix décrit une VM de dev (autologin marc, console série) construite par
l'input microvm ; ses runners sont exposés dans flake.nix pour être lancés
directement (`nix run .#dev`) et le Justfile ajoute `just vm` / `just vm-build`,
qui gardent l'état de la VM (overlay du store, socket qmp) dans
~/.local/state/microvms/<nom> (supprimer le dossier pour repartir de zéro).

Le runner passe par `path:` volontairement : ça marche même quand vms/<nom>.nix
n'est pas encore commité.
2026-09-27 13:00:56 -04:00
Hermes Agent 2622780459 feat(discord-hermes-bridge): pont Discord vers un gateway Hermes dédié
Gateway hermes-agent dédié (profil discord-bridge) sur 127.0.0.1:8643, API Server
OpenAI-compatible consommée par le cog hermes.py du discord-bot. Unité systemd écrite à
la main (le module NixOS ne gère pas d'instances) et même paquet que le bot Matrix,
donc mêmes groupes de deps (edge-tts, stt-whisper).

Clé d'API dans secrets/discord-hermes-bridge.yml, port jamais ouvert au firewall
(assertion). Côté discord-bot, HERMES_BRIDGE_URL et le nom de rôle viennent d'un
EnvironmentFile, seule la clé est secrète.
2026-09-27 13:00:56 -04:00
Hermes Agent 0000584366 feat(meetup-mcp): serveur MCP Meetup (events et groupes publics)
API GraphQL de Meetup (gql-ext) en stdio, sans authentification pour ce périmètre
(vérifié : eventSearch, groupSearch, recommendedEvents répondent sans token). Les
requêtes nominatives exigent un OAuth consumer de compte Pro : le jour où le token
arrive, il se pose dans secrets/meetup.yml et le serveur le lit via MEETUP_TOKEN_FILE,
sans changement de code.
2026-09-27 13:00:56 -04:00
Hermes Agent 7175a1fe34 feat(mcp-nixos): serveur MCP NixOS
Paquets et options NixOS/home-manager réelles (mcp-nixos, transport stdio, API
publiques, aucun secret) au lieu de les inventer.

NOTE : pas encore câblé dans services/default.nix, à importer pour l'activer.
2026-09-27 13:00:56 -04:00
Hermes Agent 2974d1616b fix(hermes-dashboard): câbler l'import du service
Le service et son secret avaient été ajoutés sans l'import dans services/default.nix :
le dashboard n'était donc jamais activé.
2026-09-27 13:00:56 -04:00
Hermes Agent bc3791d88e feat(hermes-webui): UI web de chat (profil pocket isolé, Pangolin SSO)
Paquet communautaire github:nesquena/hermes-webui (input flake) en service, agent en
process sur le profil pocket, isolé du gateway Matrix.

Deux pièges vérifiés : sans HERMES_WEBUI_ISOLATED_PROFILE=1 le serveur retombe sur le
profil par défaut et écrit dans le state.db racine partagé avec le gateway, et il n'y
a aucune garde d'authentification sur une adresse loopback (le SSO Pangolin est la
seule protection, comme pour terminal.marcpartensky.com). Le PTY (/api/pty) et l'API
complète restent donc en loopback, jamais ouverts au firewall (assertions).
2026-09-27 13:00:56 -04:00
Hermes Agent e8ff562d78 feat(gitea): forge locale (postgres, admin, Pangolin SSO)
Instance gitea sur tower avec base postgres (rôle gitea en peer auth), compte admin
créé une seule fois par un oneshot idempotent avec le mot de passe de
secrets/gitea.yml (sops). Exposition gitea.marcpartensky.com via newt/Pangolin, et
assertion pour que le port HTTP local reste fermé.
2026-09-27 13:00:56 -04:00
Hermes Agent 8134f31174 feat(jellyfin): serveur média (Pangolin SSO)
Jellyfin sur tower, répertoires de médias créés par un oneshot, groupe users en
secondaire pour traverser /home/marc (piège classique NixOS). Exposition
jellyfin.marcpartensky.com via newt/Pangolin, port jamais ouvert au firewall.
2026-09-27 13:00:56 -04:00
Hermes Agent a45363870e refactor(hermes): option enableMatrixToken, secret Matrix limité à tower
secrets/hermes-matrix.yml n'a que tower comme destinataire : déclarer le secret là
où le module est importé (laptop, anywhere) ferait échouer l'activation (setupSecrets,
« 0 successful groups required »). Le fichier devient donc une option activée sur
tower seul, et le module est enveloppé dans un bloc config = { ... } pour pouvoir
déclarer `options`.
2026-09-27 13:00:56 -04:00
Hermes Agent 88af75b94b style(hermes): thème Catppuccin Mocha, accent Lavender
display.skin = catppuccin-dark-lavender. La palette vit dans
/var/lib/hermes/.hermes/skins et est écrite au runtime, pas gérée par nix.
2026-09-27 13:00:56 -04:00
Hermes Agent 9716d34d05 feat(hermes): plugin herdr-agent-state (session résumable côté herdr)
Le code produit par `herdr integration install hermes` est vendorisé dans
services/hermes/plugins/herdr-agent-state et branché déclarativement (extraPlugins,
symlink sous .hermes/plugins, plus plugins.enabled) : plus d'installation impérative.
Il rapporte l'ID de session du pane à herdr, qui peut alors relancer le pane dans sa
conversation (`hermes --resume <id>`).

LIMITE : le plugin sort si HERDR_ENV != 1, et le socket herdr est celui de marc
(~/.config/herdr/herdr.sock, 0600) : il n'agit que pour une session lancée dans un
pane herdr sous marc, inerte (sans effet de bord) sinon.
2026-09-27 13:00:56 -04:00
Hermes Agent 5480caf847 feat(hermes): transcription locale des vocaux (faster-whisper)
Groupe de deps « stt-whisper » (faster-whisper, CPU, gratuit) plus stt.enabled : le
gateway transcrit les vocaux entrants (Element/Matrix). language = "" et pas le
défaut "en", sinon Whisper décode du français comme de l'anglais (mesuré : fr
détecté à p=0.99 sur un vocal court). Modèle « base » (140 Mo, ~5 s pour 3 s d'audio).

numpy sort d'extraPythonPackages : onnxruntime, dépendance de stt-whisper, le
fournit déjà dans le venv scellé, et un doublon fait échouer le build du paquet
hermes (collision avec le venv).
2026-09-27 13:00:56 -04:00
Hermes Agent 353b320812 perf(home-manager): useGlobalPkgs sur tower, overlays et paquets insecure
Sans useGlobalPkgs, home-manager instancie un second nixpkgs (toute la distribution
réévaluée à chaque switch). Le partage change l'ordre de merge de
nixpkgs.config.permittedInsecurePackages, un attr « dernier gagne » que plusieurs
modules redéfinissent (matrix-whatsapp, pangolin, packages.nix) : on l'unionne
explicitement dans profiles/common. L'overlay nur de zen-browser passe au niveau
système, incompatible dans le home avec useGlobalPkgs. catppuccin.autoEnable=false
coupe le scan et l'activation auto de tous les programmes HM.
2026-09-27 13:00:56 -04:00
Hermes Agent 03353679a5 feat(hermes): accès SSH à tower depuis le Mac (Hermes Desktop)
La clé ed25519 du Mac est déclarée pour l'utilisateur hermes. Déclaratif exprès :
/var/lib/hermes est en 2770 (écriture groupe, requis par le partage hermes/marc) et
sshd (StrictModes) ignore alors ~/.ssh/authorized_keys ; l'option écrit
/etc/ssh/authorized_keys.d/hermes en root 444, qui passe le contrôle et survit aux
rebuilds.
2026-09-27 13:00:55 -04:00
Hermes Agent 4c0cdc14d9 feat(hermes): partager l'état avec les sessions hermes lancées par marc
Les sessions hermes ouvertes dans un pane herdr tournent sous marc, pas sous le
compte de service : HERMES_HOME=/var/lib/hermes/.hermes (users/marc/home.nix) pour
qu'elles lisent et écrivent le même état (sessions, mémoire, lazy-python) que le
service hermes-agent.

Accès : groupe secondaire hermes pour marc (users.nix) et ACL tmpfiles sur
/var/lib/hermes (traversée) puis .hermes et .hermes/plugins (rwx + défauts ACL),
pour que les fichiers créés par marc restent lisibles côté service. C'est ce qui
rend le plugin herdr-agent-state utilisable : il parle au socket herdr de marc.
2026-09-27 13:00:55 -04:00
Hermes Agent 3c05597360 refactor(herdr): config posée par home-manager, HM de marc activée sur tower
herdr n'a ni option NixOS ni module home-manager dans l'input épinglé : sa config
(sidebar qui affiche le modèle hermes de chaque pane) passe par xdg.configFile dans
modules/home/herdr, importé par users/marc/home.nix. force = true car le premier
switch remplace le symlink posé avant par systemd.tmpfiles, que check-link-targets
ne reconnaît pas comme un fichier home-manager-files (activation en status 1 sinon).

tower active home-manager.users.marc = users/marc/home.nix, le même profil que
`HM=marc just home` : herdr et le reste des dotfiles arrivent avec `just nixos`.
backupFileExtension = hm-backup pour la première bascule. Entre `just nixos` et
`just home`, c'est le dernier switch qui écrit les liens.
2026-09-27 13:00:55 -04:00
Hermes Agent c47f60a129 feat(ssh): add hermes host configuration 2026-09-26 19:40:04 -04:00