hermes@tower, connecté en ssh sur marc@mac, doit lancer les rares
opérations root du toolchain Xcode sans mot de passe : bascule de
xcode-select, acceptation de la licence, runtime du simulateur.
Fragment sudoers.d dédié (security.sudo.extraConfig est déjà posé par le
bloc terminfo de nix-darwin), scopé aux trois shims
/usr/bin/{xcode-select,xcodebuild,xcrun} ; le reste du sudo de marc reste
inchangé. Vérifié : visudo parsed OK, éval du fragment et du toplevel.
Deux agents separes au niveau OS (utilisateurs anna et yves, HERMES_HOME dedie, tmpfiles + ExecStartPre qui recree le squelette du home en mode managed), outils dangereux desactives et /api/pty comme /api/files bloques par nginx. Exposes en hermes-anna et hermes-yves.marcpartensky.com ; identifiants hors store nix sous /var/lib/hermes/guests.
ExitOnForwardFailure=yes sur l'autossh du Mac : un forward rate (port deja pris, sshd pas encore pret au boot) ne laisse plus une session inutile, launchd reessaie. La cle du Mac (marc@Air-de-Marc) est autorisee sur tower et sur le deck : ssh tower et ssh deck passent par rack en ProxyJump.
mk8dx selectionne le dump de base (Title ID 0100152000022000, sinon un fichier hors update/DLC, sinon le premier .nsp/.xci) au lieu du MK8DX.xci code en dur : Eden applique seul l'update pose a cote du jeu, mais lancer le NSP d'update comme s'il etait le jeu echoue. La tuile Gaming Mode passe par ce script.
tower fait routeur pour son LAN : ip_forward et NAT wg1 -> wlan0 (sortie avec l'IP LAN 192.168.1.44), et le pair tower cote VPS declare desormais 192.168.1.0/24 dans ses allowedIPs. Le Steam Deck et le reste du LAN deviennent joignables depuis rack sans dependre d'un forward de la box.
Timer de 5 minutes qui remet 100.89.128.1/24 et la route du 100.89.128.0/24 sur wg0, et reinsere l'exception iptables INPUT pour 100.89.128.0/24 : tailscaled jette cette source recue sur une interface autre que tailscale0, ce qui avait coupe le tunnel Pangolin 6h40 le 23/10. Complement de gerbil-wg0-ensure.nix, qui ne couvre que le demarrage de gerbil.
Le controleur headscale du VPS passe en mode durci : flotte DERP de Tailscale retiree (derp.urls vide), DERP embarque sur le VPS (region 900, verify_clients) et STUN en UDP 3478 ; route Traefik headscale.marcpartensky.com -> 127.0.0.1:8090. Cote clients, services/tailscale remplace l'ancien secret tailscale/auth_key (absent) par headscale/preauth_key, coupe l'envoi de logs vers Tailscale Inc (disableUpstreamLogging) et est importe sur tower, le deck et anywhere.
L'app se build sur le Mac en trois commandes, le toolchain restant dans le
devShell du flake winnie (jamais installé sur le Mac) :
cd ~/git/nixos && just mac # déploie ce setup
winnie-sync # attrape ~/git/winnie depuis tower (rsync ssh)
winnie-ios # simulateur ; npm ci + tauri ios init au besoin
- modules/home-mac/winnie : winnie-doctor [--fix], winnie-sync [--delete],
winnie-shell, winnie-front, winnie-macos, winnie-build-macos, winnie-ios,
winnie-build-ios, winnie-verify. Scripts en writeShellApplication (shellcheck
au build) ; scripts.nix est séparé du module pour être constructible depuis
tower avec les pkgs linux et testable sans Mac.
- profiles/macos : flakes + trusted-users dans nix.conf, et
system.activationScripts.winnie-xcode (xcode-select -s, licence Xcode,
-runFirstLaunch) pour que seule l'installation App Store reste manuelle.
- Embarque aussi le setup SSH entrant du Mac (sshd, clé hermes@tower, tunnel
inverse autossh) qui était déjà dans l'arbre de travail.
Vérifié depuis tower : nix eval du darwinConfigurations.macos (toplevel et
home-manager-generation) + build des scripts en x86_64-linux (shellcheck) et
rsync de bout en bout depuis le dépôt de tower.
Paquets yggdrasil + tor et deux launchd.daemons (tor SOCKS 127.0.0.1:9050,
yggdrasil sur /etc/yggdrasil.conf) pour faire entrer le Mac dans le mesh.
/etc/yggdrasil.conf (mot de passe partagé) reste hors du store, à créer
une fois à la main ; le torrc ne contient aucun secret.
Module services/ygg-mesh : Yggdrasil en réseau privé (mot de passe partagé,
clés publiques épinglées), liens Tor via une instance tor dédiée (onion
service par machine) et lien direct multicast prioritaire sur le LAN.
Chaque machine garde une adresse IPv6 stable et un nom <host>.ygg.
Secret dans secrets/ygg-mesh.yml (règle .sops.yaml dédiée) ; config rendue
à chaud au démarrage (ExecStartPre + credential systemd), le mot de passe
ne touche jamais le store. Identités et clés dans la table `nodes`.
stalwart-mcp (Rust) parle JMAP au Stalwart du VPS, patche pour l'URL
API et l'envoi depuis l'identite marc. Mot de passe dedie dans
secrets/stalwart-mcp.yml ; importe par tower seulement, pour eviter
le conflit de cle sops avec services/stalwart sur anywhere.
Le mineur ne tourne que 01:00-09:00, plus en semaine 09:00-18:00
quand un evenement du calendrier sg est actif. Le wallet vient de
secrets/monero.yml via LoadCredential (plus dans la ligne de
commande) ; meme planning sur le Deck.
Le forward de box 77.207.176.170:42070 est mort : tower devient pair
client du hub wg1 avec persistentKeepalive. L'alias ssh tower pointe
sur 10.100.0.3 et la cle root du VPS est autorisee sur tower. Cle
privee dans secrets/wireguard.yml (recipient tower).
secrets/zitadel-smtp.yml porte le mot de passe du compte d'envoi pour
le provisioning SMTP par API (v2 ignore la config runtime). Le PAT
admin est materialise en 0400 pour hermes et rotate.
anki-mcp : Anki sans bureau et addon AnkiMCP, HTTP MCP sur 3141,
connecte a la collection du serveur de sync.
mcp-lan-access republie sur l'adresse LAN de tower les endpoints
loopback (3141, 8710, 6060, 23373), firewall limite au Mac ; l'addon
Anki autorise ce Host (anti DNS-rebinding).
arr-mcp ne publie plus 6060 sur 0.0.0.0. Le module mcp-lan-access
est importe par services/default.nix avec anki-mcp, wise-mcp et
bank-mcp.
- gerbil-wg0-ensure.nix : supprime wg0 sans adresse avant le demarrage de gerbil, sinon plus aucun trafic ne passe dans le tunnel newt.
- vaultwarden-mcp commente : son secret vit dans secrets/tower.yml, illisible sur anywhere, ce qui cassait setupSecrets a chaque activation.
- zitadel/steps retire : le secret etait chiffre en type:int, refuse par sops-install-secrets ; l'instance est deja initialisee.
Le 12/10/2026 le disque de 46 G est monte a 100 % : pangolin-pre-start a echoue en « No space left on device » et traefik/gerbil sont tombes en cascade (plus rien sur 80/443). --delete-older-than 30d laissait ~18 G de generations et journald montait a 4,1 G (10 % par defaut). 14 j et SystemMaxUse=500M laissent de la marge.
- services.hermes.enableAgent = false : le chat est inerte sur le VPS (aucun token Matrix/Discord, modele DirectSDK sans login claude) et tirait claude-code (unfree) dans le build. L'utilisateur hermes, sa cle SSH et le sudo nixos-rebuild restent : c'est par la que tower deploie en remote
- home-manager.users.marc : le profil marc (geminicommit, etc.) est installe sur le VPS
Module services.llm-steamdeck, desactive par defaut (enable a passer a true dans le profil deck, cf. README) : llama-server en Vulkan sur RADV, GGUF telecharge depuis Hugging Face au premier demarrage, web UI, limites memoire pour les 16 Go unifies. Importe par services/default.nix (donc inerte sur laptop/tower) et par profiles/deck.
- services/cage-waydroid : waydroid dans un cage HEADLESS, expose en VNC standard (wayvnc 5902, auth DES = le seul mode que macOS Screen Sharing negocie), plus un pont noVNC sur 127.0.0.1:6082
- root volontaire : waydroid-net.sh cree le bridge waydroid0 (CAP_NET_ADMIN) et la session waydroid est un SINGLETON global, c'est ce service qui la detient
- tower : virtualisation.waydroid.package = waydroid-nftables, le noyau n'a que nf_tables (le waydroid-net.sh standard sort en « iptables (legacy): can't initialize iptables table nat »)
- newt : ressource android.marcpartensky.com -> 127.0.0.1:6082 derriere le SSO Pangolin
- modules/nixos/kasmvnc-chrome-cdp.nix : lance un Chromium dans le desktop KasmVNC avec --remote-debugging-port=9222, profil persistant /home/marc/chrome-cdp-profile
- Le MCP Playwright s'y attache (--cdp-endpoint http://127.0.0.1:9222) : les actions d'automatisation se font dans CETTE fenetre, donc visibles en direct sur le bureau distant (8443 en LAN, kasm.marcpartensky.com)
- CDP reste sur 127.0.0.1 : un port CDP joignable donne le controle total du navigateur par quiconque l'atteint, donc jamais au LAN ni via Pangolin
- newt : healthcheck HTTP sur le vhost local 8288 (KasmVNC repond 200 sur "/" avec disableBasicAuth) ; sans lui la cible sortait du load-balancer
Noyau 6.18.54 avec ANDROID_BINDER_IPC/BINDERFS/MEMFD_CREATE : pas de module out-of-tree ni reboot. waydroid-container echoue proprement tant que 'waydroid init' n'a pas ete lance une fois (root, ~1,2 Go d'images).
KasmVNC etant un serveur X, Plasma tourne en session X11 (startplasma-x11) avec une arborescence de donnees isolee (plasmaDataEnv + plasmaConfigDir) exportee uniquement dans l'unite, sans toucher a la session niri locale de marc.
- desktop = "plasma" : xstartup startplasma-x11, look-and-feel org.hermes.kasm.desktop (konsole + LibreWolf epingues)
- disableBasicAuth : le SSO Pangolin gate deja kasm.marcpartensky.com, fin du double login kasmvncpasswd
- setxkbmap ajoute au PATH (kded6 configure les claviers via ce binaire)
Rustguac : guacd en loopback (tls=false) + vhost guac.marcpartensky.com
(sans ACME, TLS par Pangolin). KasmVNC : display :20 (pas :1, session X
existe deja), desktop lxqt (lxqt-wayland refuse), mot de passe regeneré
par empreinte sops, auth HTTP 200/401 testee. Rustdesk : ports reels 1.1.16,
hbbs/hbbr corriges; nginx guac/kasm en loopback. Vault/rustguac secrets
lues par le bon user (vault, rustguac, marc) au lieu de root. WireGuard
client sur wg1 (10.100.0.3/32, endpoint VPS 104.129.12.158:443) desactive
tant que le secret sops wireguard/tower_private_key n'existe pas (evite
le blocage sops-nix sur tout le build). hermes.extraGroups += systemd-journal.
services/nextcloud/password.txt était committé en clair ("nextcloudpassword")
depuis le 25/11/2025, jamais référencé dans la config, exposé publiquement
sur github/codeberg depuis. Supprimé.
adminpassFile ne fixe le mot de passe QUE lors de l'install initiale (occ
maintenance:install) : sur une instance déjà installée il est ignoré, donc
juste changer le secret sops n'aurait pas suffi. Ajout d'un ExecStartPost
sur nextcloud-setup qui force le mot de passe du compte root à la valeur
sops à chaque activation (self-healing).
Vérifié sur tower : ancien mot de passe "nextcloudpassword" -> 401 après
le switch, hash oc_users.password changé.
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.
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.
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).
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`.
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.
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.
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.