L'emulateur etait le maillon manquant : la capture tournait deja en service, mais la cible
avd ne vivait que si une session interactive la lancait.
- android-emulator : AVD headless avec -tcpdump vers pcap/avd/. JAVA_HOME force au JDK 17
qu'androidenv utilise lui-meme, parce que le runner appelle la version non encapsulee du
SDK, celle qui reclame JAVA_HOME et sans laquelle l'AVD n'est jamais cree.
- android-avd-install : timer qui installe au boot les APK deposes dans apks/.
- aucune unite bloquante : ni wantedBy sur une oneshot d'installation, ni ExecStartPost qui
attend le boot Android. Une unite laissee en cours de demarrage bloque toute activation
nixos-rebuild, qui sort en « unit already loaded ».
- le dossier apks/ est cree par le service, une regle tmpfiles ne suffisait pas.
Verifie sur tower : switch code 0, qemu actif sous le service, emu.pcap ecrit et croissant
sous l'utilisateur de capture, co.hinge.app installe dans l'AVD du service.
Une cible = une instance Android, donc une interface et ses propres fichiers : c'est la
seule isolation franche du trafic par appli, et elle ne demande aucun root.
- waydroid : capture sur le bridge waydroid0.
- avd : alimentee par le -tcpdump de l'emulateur, qui sort par la pile reseau de l'hote.
- rotation de 10 min, 72 fichiers conserves (12 h), digest d'hotes par cible.
Pas de root : CAP_NET_RAW et CAP_NET_ADMIN en capacites ambiantes, donc NoNewPrivileges
reste a false (systemd refuse la combinaison). Utilisateur statique et non DynamicUser,
plusieurs unites partageant le meme arbre d'etat. marc et hermes sont ajoutes au groupe
pour lire les captures sans root.
Verifie sur tower : tcpdump a l'ecoute sur waydroid0, deux jeux de pcaps distincts, digests
ecrits par les timers (avd : connectivitycheck.gstatic.com ; waydroid : play.googleapis.com).
Les lignes du sélecteur de modèle SANS suffixe [1m] (claude-opus-5-5, claude-opus-5, claude-sonnet-5) passent par le provider natif anthropic, pas par claude-subscription-directsdk. Sans le paquet python anthropic dans le venv scellé, une session ouverte sur une de ces lignes meurt en agent_init_failed : "The 'anthropic' package is required for the Anthropic provider" (lazy installs désactivés par le packaging nix).
Auth du provider natif : aucune clé API à poser, agent/anthropic_credentials.py prend l'OAuth de l'abonnement dans ~/.claude/.credentials.json (refresh et réécriture gérés par Hermes), ou un grant Hermes via hermes auth add anthropic --type oauth.
Les lignes AVEC [1m] (provider claude-subscription-directsdk, CLI claude) ne changent pas. Supprime aussi la ligne commentée devenue doublon : extraDependencyGroups n'est défini qu'une fois.
Token créé dans Gitea (compte mazex, son compte SSO Zitadel). Débloque le serveur MCP gitea (GITEA_ACCESS_TOKEN_FILE) et les opérations git/API sur git.marcpartensky.com, dont le miroir des repos GitHub.
MCP stdio lancé par hermes-agent sur tower ; parle au Mac en ssh (alias
maclan puis mac, clé hermes). Tools : status (winnie-doctor + révisions),
sync, doctor_fix, xcode_fix (3 opérations root via la règle sudo
NOPASSWD xcode-select/xcodebuild/xcrun), runtime_install et les builds
(arrière-plan, suivi par log_tail) : ios_init, ios_build_sim,
macos_build.
Vérifié : pycodestyle/pyflakes, build de la dérivation, sonde stdio
(tools/list + appels réels sur le Mac), éval du toplevel avant commit.
L'ancien câblage ne pouvait pas marcher : client_id littéral "gitea"
(impossible, Zitadel génère les client_id) et oneshot qui échouait à chaque
boot sur --enabled (flag inexistant en Gitea 1.27.x), avalé par `|| true`.
- App Zitadel "Gitea" (projet marcpartensky) : appId 396570385799184684,
clientId 396570385799250220, type Web, redirect
https://git.marcpartensky.com/user/oauth2/zitadel/callback
- oneshot gitea-oidc-init : add-or-update (id de login_source via psql),
secret lu depuis sops à chaque exécution, idempotent même en dérive
- [openid] d'app.ini : OpenID 2.0 legacy, désactivé (sans rapport avec OIDC,
échouait en "rel=openid2.provider not found" avec une URL Zitadel)
- [oauth2_client] : ENABLE_AUTO_REGISTRATION, USERNAME=email,
ACCOUNT_LINKING=login (page de liaison unique pour le compte local marc)
- ressource Pangolin : auth.sso-enabled=false (auth Gitea seule, une seule
couche, clients git/API à token non bloqués par un redirect SSO)
- secrets/gitea-oidc.yml : vrai oidc_client_secret (chiffré, clé tower)
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.
Le premier bootstrap avait laisse un layout Garage a zero noeud (quorum de 0, inapplicable) : purge unique de meta/data avant le demarrage du service, winnie-bucket reprovisionne bucket, cle et s3.env. L'ingest passe de Type=oneshot a Type=exec pour que RuntimeMaxSec s'applique, et S3_ENV_FILE force le redemarrage du backend quand Garage est provisionne apres son premier demarrage.
postgresql.service est Type=notify : sans after et requires, le oneshot qui pose le mot de passe de la base partait en parallele et mourait sur « connection to server on socket /run/postgresql/.s.PGSQL.5432 failed » (boots du 22/10 20:29 et du 23/10 09:37).
enabled=false, send=false et offer_version=2 ecrits dans config.yaml : la question de partage des stats ne revient plus a chaque session (le defaut ne compte pas comme reponse) et rien n'est collecte.
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.
services/hermes-pocket devient services/hermes-mobile : le backend de l'appli F-Droid sert le profil default (meme historique, memoire, skills et modele que le gateway Matrix et le dashboard) au lieu du profil isole pocket, en gardant la porte d'auth native (mobile-serve.env). Le nom de ressource Pangolin reste hermes-pocket : le renommer recreerait une ressource sur un domaine deja pris.
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.
secrets/switch-keys.yml (prod.keys d'Eden sur le deck, posees dans le home de marc) et secrets/headscale.yml (preauth_key reutilisable, consommee par services/tailscale sur tower, le deck et le VPS). Regles de creation sops associees dans .sops.yaml.
Le Mac expose deja son sshd (services.openssh dans profiles/macos) et son
tunnel inverse autossh (rack:2223), il manquait les alias cote marc.
- maclan = marc@192.168.1.48 (LAN, IP DHCP)
- mac = marc@localhost:2223 via rack (tunnel inverse, hors LAN)
Verifie en construisant le fichier genere (hm_.sshconfig) : les deux entrees
sortent avec le bon HostName/Port/ProxyJump.
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`.
onedark.transparent couvre tous les groupes du theme, pas seulement
Normal ; les highlights Lualine sont nettoyes apres ColorScheme et
les ~ de fin de buffer deviennent des espaces.
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).
Renomme stalwart_mail_pw2/pw3, spam_pw, noreply_pw, admin_pw, bob_pw
et acme_secret en stalwart_*_password / stalwart_acme_secret, un
fichier sops par usage.
66.108.44.154 passe en allowed-ip : l'auto-ban persiste en base et
bloquait le domicile sur 25/465/993.
meetup@marcpartensky.com partage la boite de marc.
Les blobs common.yml et anywhere.yml sont re-chiffres dans le meme
commit (renommage des cles Stalwart, rotation, postgres_crt/key).
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.
dashboard.public_url engage auth_required : la racine ne sert plus le
token de session en clair derriere Pangolin. Le flux client passe par
/auth/password-login puis un ws-ticket a usage unique. nginx annonce
https et la sonde devient /api/status.
App Zitadel publique en PKCE (client_id 395733475048620332), claim
preferred_username limite a marc@marcpartensky.com, redirect explicite
car nginx reecrit le Host. SSO Pangolin coupe pour eviter le double
login.
DeepSeek v4.1 Flash devient le modele par defaut ; chaine de secours
DeepSeek puis Nemotron 3 Ultra gratuit ; le salon de Zoe (Matrix) y
passe aussi.
Beeper est declare dans les mcpServers avec le token lu depuis
l'environnement (plus de token en dur dans config.yaml) et l'URL LAN
pour etre cliquable depuis Hermes Desktop. Le timeout du MCP gitea
est complete.
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.
Input brut hermes-menagerie (github:ZakiChair/hermes-catppuccin),
module home-mac/hermes-skins qui installe les palettes dans
~/.hermes/skins, active dans la home de marc@macos.
- 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.
- secret oidc_env (secrets/winnie.yml, chiffre pour tower) materialise par le oneshot winnie-oidc-secret dans /var/lib/winnie/oidc.env, requis par winnie-backend (EnvironmentFile non optionnel)
- PKCE : pas de client_secret cote backend
- .sops.yaml : creation_rule pour secrets/winnie.yml
Ressource proxy-resources.sonarr -> 127.0.0.1:8006, healthcheck /ping, meme schema que radarr (proxy-resources + protocol, l'ancien schema que comprend le Pangolin du VPS). SSO actif et auth de l'appli coupee : sans SSO l'UI complete et l'API v3 seraient ouvertes a Internet.
- urlbase = "localhost" (recopie de l'exemple du module nixpkgs) faisait rediriger en 307 TOUT chemin hors base, /api/v3/... compris : les clients API locaux recevaient la page de login. Radarr, Sonarr et Readarr sont servis a la racine du domaine
- settings.auth.method = "External" : l'auth de l'appli ne filtre rien derriere le tunnel newt (les requetes distantes arrivent de 127.0.0.1, donc vues comme locales) et la porte reste le SSO Pangolin. Ni Radarr 6.x ni Sonarr 4.x n'ont d'OIDC natif (arrive dans Sonarr 5)
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
Politique du 13/10/2026 : le shell n'attend plus de validation avant d'executer. « off » est un bypass teste AVANT les branches cron / single_query / unattended, donc il coupe aussi les refus par defaut en contexte headless. Restent actifs malgre off : la blocklist hardline code-shippee et les regles approvals.deny (vides ici).
Le module melangeait l'acces (utilisateur hermes, cle SSH, sudo nixos-rebuild, python3 systeme pour le probe SSH de Desktop, git safe.directory) et le gateway lui-meme : couper le chat sur un hote ou il est inerte retirait aussi le moyen de s'y connecter et d'y deployer. config passe en lib.mkMerge : le bloc acces s'applique toujours, le gateway (postgres, MCP, claude-code unfree, service hermes-agent) seulement si enableAgent.
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
- ExecStartPre tue toute Xvnc sur le display configure puis purge lock et socket avant de demarrer (une session precedente orpheline tenait :20 apres un switch : « A VNC server is already running », exit 29, crash-loop). Le display est passe en ARGUMENT dans la meme commande : en liste, systemd executerait chaque element comme une commande separee.
- ConditionUser=marc : l'unite est installee dans /etc/systemd/user et hermes demarre aussi un user manager linger avec default.target actif ; sans ca il lançait une deuxieme instance sur :20 et son activation utilisateur echouait au switch (rc=4).
- winnie-frontend : build Vite (app/dist) servi par static-web-server sur 8888, aligne avec la ressource Pangolin winnie-frontend (un desaccord = 502, port en cache cote newt)
- newt : nouvelle ressource dioxus-frontend (dioxus.marcpartensky.com)
La chaine de secours hermes passait de inkling:free a nemotron (meme modele, pas de basculement vers un modele different). openrouter-mcp ecrit aussi le default_model nemotron dans sa config.toml.
Trois binaires dans le profil systeme, patron de services/amazon-mcp :
- hinge-auto-login chromium visible (telephone + SMS), session persistee dans /var/lib/hermes/hinge-auto/user-data
- hinge-auto-like boucle de likes headless sur Discover (HINGE_MAX_LIKES defaut 40, detection de fin de flux)
- hinge-auto-calibrate dump des boutons pour affiner les selecteurs
Profil partage hermes <-> marc via ACL tmpfiles. Garde-fous : limite ~8 likes/jour gratuite Hinge, arret sur marqueur de fin.
- Variables sans underscore (GOTIFY_OIDC_CLIENTID, ...) : les formes snake_case sont ignorees en silence par Gotify 3.x
- LISTENADDR 127.0.0.1 (exposition via newt/Pangolin uniquement), SSO Pangolin desactive : les clients natifs (appli Android, gotify-cli, scripts /message) ne suivent pas de redirection navigateur
- OIDC_LINK_BY_USERNAME + AUTOREGISTER : rattache l'identite Zitadel au compte local renomme
- after/wants newt + StartLimitIntervalSec=0 : le discovery OIDC 503 au boot si le tunnel n'est pas monte
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.
Stub HTTP + registration synapse + login unique. Registration sous
/var/lib/matrix-marc-agent-as (StateDirectory) : sous /var/lib/hermes/.matrix
(0700) synapse ne pouvait pas la lire, et ReadWritePaths sur un dossier absent
faisait echouer l'unite en 226/NAMESPACE, ce qui bloquait le switch.
sops-install-secrets échouait sur ce fichier ('Could not decrypt with
AES_GCM: cipher: message authentication failed'), ce qui bloquait TOUT
nixos-rebuild switch sur tower (pas seulement les services concernés).
Recréé avec une nouvelle valeur aléatoire pour les deux clés partagées
(hermes_discord_bridge_env, discord_bot_hermes_bridge_env) : secret
purement interne (loopback 127.0.0.1, jamais exposé), la rotation ne
casse rien côté consommateurs (discord-bot, hermes-discord-bridge, API
server par défaut) puisqu'ils relisent tous la même valeur au prochain
switch.
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é.
Modules NixOS pour une gateway d'accès distant multi-protocole : rustguac
(remplacement Guacamole, OIDC, audit, enregistrement), kasmvnc (bureau
Wayland LXQt), rustdesk (relais P2P hbbs/hbbr), vault-rustguac (Vault en
mode dev pour stocker les identifiants de connexion des deux premiers),
plus les vhosts nginx associés.
Importés dans services/default.nix mais NON activés sur aucun profil
(enable reste false partout) : domaines (guac.example.com, auth.example.com),
token Vault dev et secret OIDC sont encore des placeholders TODO dans les
modules, à finir avant tout services.*.enable = true.
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'.
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).
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).
- 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)
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.
/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
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).
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.
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.
- 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)
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).
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.
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).
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.
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).
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.
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.
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).
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.
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.
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.
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é.
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.
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.
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.
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).
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é.
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.
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`.
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.
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).
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.
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.
Updates the Kitty terminal configuration to use the Catppuccin Mocha color scheme.
This includes changes to background, foreground, cursor, selection, URL colors,
and adds the full set of ANSI color definitions.
Backend hermes-agent en mode dashboard (9120) + nginx host-rewrite (9121),
ressource newt terminal.marcpartensky.com. Ports jamais ouverts au firewall :
/api/pty est un shell.
nginx sur 0.0.0.0:8092, root /var/lib/hermes-files (répertoire dédié : le
stateDir /var/lib/hermes est en 0770, nginx ne peut pas le traverser).
Autoindex, aucune auth : rien de sensible dedans, jamais routé via Pangolin.
- services/matrix : synapse 1.160, listener 127.0.0.1:8008, DB postgres,
registration_shared_secret généré (hermes ne peut pas poser de secret sops
root-only)
- matrix-discord/matrix-meta : ponts mautrix ; fix matrix-meta : synapse
rejoint le groupe mautrix-meta-registration (sinon il ne peut pas lire
meta-registration.yaml, tout le homeserver refuse de démarrer)
- matrix-dumps : dump périodique + clés pickle des ponts (déchiffrement megolm)
- matrix-hermes (mxc) : compte admin @hermes-admin auto-provisionné depuis le
registration_shared_secret, token utilisable par l'agent pour l'admin API
Synapse (fabriquer un token pour n'importe quel compte local)
Clé hermes@tower déclarée en authorizedKeys : sur hermes lui-même (accès aux
hôtes qui importent services/hermes), en root déclaratif sur anywhere (le
bloc était commenté), et compte système hermes complet + sudo NOPASSWD
nixos-rebuild sur deck (qui n'importe pas services/hermes).
Homeserver matrix.marcpartensky.com, @hermes:matrix.marcpartensky.com, E2EE
required (salles de pont chiffrées), pas de mention requise ni d'auto-thread
dans les salles de pont (3+ membres). Allowlist : @marc + son ghost Signal.
Token dans secrets/hermes-matrix.yml (règle .sops.yaml dédiée, sopsFile
explicite car hors de tower.yml).
commonServiceConfig posait NoNewPrivileges=true sur hermes-agent.service et
hermes-backend.service : le noyau ignore alors le bit setuid, donc sudo/su
refusaient net dans toute session lancée depuis Matrix ou le terminal web,
rendant la règle NOPASSWD nixos-rebuild inopérante. mkForce false sur les deux
unités ; sudo reste borné à la liste de commandes déjà déclarée.
- défaut : claude-sonnet-5 (DirectSDK, abonnement Pro/Max) au lieu de DeepSeek
via OpenRouter ; consomme le quota à chaque message, surveiller l'usure
- fallback_providers réordonné : gratuits OpenRouter (inkling, nemotron ultra)
puis DeepSeek Flash en tout dernier recours (payant mais bon marché)
- agent.reasoning_overrides : le niveau de reasoning suit le modèle actif
(DeepSeek Flash/Sonnet 5 -> high, Opus 5 -> max)
- settings.platforms.matrix.channel_overrides : 3 salons épinglés sur Opus 5
ou Sonnet 5 (abonnement), le reste reste sur le défaut
package.python.pkgs suit désormais la famille python du venv (nix/pythonLock.nix,
3.14) au lieu de la nixpkgs figée du flake hermes-agent (hermesPkgs, 3.12) qui
filtrait silencieusement les paquets. Ajoute extraDependencyGroups = matrix +
edge-tts (résolus par uv dans le venv scellé, préparant le bot Matrix et le TTS
Edge).
Add mautrix-linkedin, mautrix-meta (Instagram, Messenger), and mautrix-telegram (initial setup).
Enable E2EE by default for mautrix-discord and mautrix-signal, ensuring stable pickle_key generation.
Update matrix-synapse dependencies for new bridges.
Deuxième voie d'accès VNC, indépendante de la session niri :
backend headless de wlroots, donc aucun besoin de vkms ni d'écran branché,
et rien qui touche la session locale. Service system, démarre au boot sans
login. Exposé en noVNC sur 6081, wayvnc reste sur loopback 5901.
Points de mise au point validés au banc d'essai :
- la sortie headless n'annonce que 1280x720 mais accepte tout via
wlr-randr --custom-mode, posé AVANT wayvnc qui fige la taille à sa connexion
- cage démarre son propre XWayland, une appli X11 marche aussi
- firefox exige que le dossier de profil existe déjà, sinon Profile Missing
- profil dédié dans /var/lib/cage-firefox/profile, séparé de celui de marc
Introduces a dedicated PostgreSQL database and schema for music data,
including playlists, tracks, and various analytical views. This service
is designed for importing Spotify playlists into YouTube Music.
Updates the codeberg-mcp dependency hash to SRI format. Refactors
home-manager package names for prettier and neovim-node-client.
VKMS expose une liste de modes dont 1920x1080, donc pas de mode custom :
on déclare le mode de la sortie Virtual-1 via programs.niri.settings.outputs.
Niri relit sa config à chaud, un just home suffit, pas de relogin.
Résolution paramétrable par virtualWidth / virtualHeight en tête du module.
Update nixpkgs and nix-darwin to 26.05.
Enable vkms kernel module for the tower profile to provide a virtual display.
Configure mautrix-signal and mautrix-discord services.
Update matrix-synapse dependencies to wait for new bridges.
services.hermes-agent.extraPackages était défini une fois pour claude-code et une
seconde fois pour nodejs_22 (MCP GitHub), ce qui cassait l'évaluation de
nixosConfigurations.tower : "attribute 'services.hermes-agent.extraPackages'
already defined". Les deux paquets sont maintenant dans une seule liste.
Un input "path:" relatif laisse un noeud non verrouillé dans flake.lock, que les
nix anciens (<= 2.20) refusent ("lock file contains mutable lock") : c'est ce qui
cassait `just mac` sur le Mac. Le sous-flake ./protonmail-mcp est maintenant appelé
directement (import de son flake.nix, inputs passés explicitement) et sa dépendance
externe proton-mail-bridge-client devient un input github normal, donc verrouillé.
Même rev qu'avant (811be5d) : aucun changement de version du paquet.
Integrates new Model Context Protocol (MCP) servers for Codeberg and GitHub.
The Codeberg MCP server is a new service definition.
The GitHub MCP server is added to the Hermes agent configuration and requires
Node.js 22 as an extra package for `npx`.
Refactors the wayvnc startup mechanism. It is now launched directly by niri
using `spawn-at-startup` instead of a systemd user service. This change
resolves an issue where wayvnc could not find the Wayland display due to
missing `WAYLAND_DISPLAY` in the systemd service environment.
Configure websockify to listen on 0.0.0.0:6080 and open port 6080 in the firewall,
allowing direct LAN access to the noVNC web client. Update access documentation.
Switch the default AI model for Hermes from Claude Sonnet to DeepSeek V4.1 Flash
(OpenRouter) and adjust the fallback provider chain.
Integrates noVNC with websockify to provide a web-based VNC client
for wayvnc, accessible via SSH tunnel on port 6080.
Adds a new Headscale ACL policy for the personal tailnet, enabling
full mesh connectivity between all nodes on all ports.
Set kernel panic to reboot after 10 seconds.
Enable systemd watchdog for automatic reboot on freeze.
Add ZFS root key to initrd secrets.
Enable the Roku service.
This introduces a new `hermes-agent` MCP server for Roku TVs, allowing control over key presses, brightness, app launching, and status queries via the Roku ECP API.
- input hermes-agent 0.21.2 -> 0.21.4 (requis par le plugin directsdk)
- claude-code 2.1.223 : extraPackages du service + systemPackages
- provider par défaut : claude-subscription-directsdk-experimental (claude-sonnet-5)
- vision auxiliaire épinglée sur kimi pour préserver le quota Claude Pro
Integrates the `duaragha/amazon-shopping-mcp` server.
Uses Playwright/Chromium for Amazon interactions.
Configured as a `hermes-agent` subprocess.
Includes `amazon-mcp-login` helper for manual session setup.
Introduces the Matrix homeserver (Synapse) and the mautrix-whatsapp bridge.
Configures Synapse with PostgreSQL, including specific collation requirements.
Sets up secret generation for both services and manages their startup order.
The `nextcloud-setup` service now forces a re-run and executes `occ upgrade` to ensure all app tables are created. This resolves 500 errors for CalDAV due to missing calendar tables.
Also, temporarily disable the `kanidm` service and re-encrypt the `hermes_env` secret.
The container needs to access Nextcloud on the host's 127.0.0.1.
Without host networking, 127.0.0.1 inside the container does not point
to the host, leading to Nextcloud 400 errors due to trusted_domains.
Configures Nextcloud MCP in single_user_basic mode, exposed on
127.0.0.1:8710 and integrated with Hermes.
Refactors Neovim config to use system nixpkgs input, preventing
duplicate evaluations and warnings.
Removes --upgrade flag from nixos-rebuild in Justfile.
Introduce base configurations for macOS and Nix-on-Droid hosts.
The macOS configuration sets up Nix-darwin with home-manager, essential system packages, keyboard remapping, and disabled Homebrew.
The Nix-on-Droid configuration provides common environment packages, home-manager integration, and Nix flake support.
Allow `marc` and `hermes` to run `nixos-rebuild` without password.
Configure `git` for root to access user's flake repository.
Set `tmpfiles` ACLs to grant `hermes` necessary permissions.
Prevent `createHome` for `marc` to avoid breaking `hermes` ACLs.
Temporarily disable `radarr` service.
add custom provider `kimi-k3-global` for Moonshot API.
set default model to `kimi-k3` with vision and large context.
configure agent and auxiliary vision with max reasoning effort.
update hermes_env secret for new configuration.
Add Home Manager module for `aichat` CLI, integrating Moonshot/Kimi API.
Uses sops-nix for API key management.
Add `spotify-mcp-server` as a system service, integrated with Hermes.
Manages Spotify credentials via sops-nix.
Enable `nextcloud` OIDC app.
Configure `nextcloud-mcp` to restart on sops secret changes.
Enable `zitadel` service.
Configure the hermes agent to use moonshot kimi, replacing anthropic
claude sonnet. Update `hermes_env` secret. Comment out beeper mcp
server and add commented-out nextcloud mcp setup.
Pin nixvim to nixos-26.05 by updating its nixpkgs input.
Configure time zone and disable automatic-timezoned service for the deck profile.
Add numerous CLI and GUI tools for the deck user via home-manager modules.
Include direnv setup and a desktop shortcut for returning to Gaming Mode.
Update home.stateVersion and set EDITOR/VISUAL variables.
Configures Eden (yuzu fork) and Ryubing (Ryujinx fork) emulators.
Includes a script and desktop entry for Mario Kart 8 Deluxe.
Sets up game directories, enables Bluetooth, and allows an optional firewall port.
Disable automatic app updates and the app store.
Add `overwritecondaddr` and `trusted_proxies` to ensure Nextcloud correctly handles requests when behind a reverse proxy.
Enable the hermes-agent service with a default model and sops secret.
Also update the `mac` recipe in `Justfile` to include `extra-experimental-features` for nix-darwin.
Integrates `steam-config-nix` for managing Steam settings.
Configures `jovian.devices.steamdeck` with auto-update and gyro DSU.
Sets up `programs.steam.config` for Proton GE and non-Steam apps.
Disables `jovian.decky-loader`.
Adds a new age key for the 'deck' machine to the sops configuration.
Re-encrypts common secrets to include the new recipient.
Also updates .gitignore to ignore all 'result*' files.
Integrate Plasma 6 as the default desktop environment for the Steam Deck.
Introduce a new `deck-iso` system for generating an installable ISO.
Refactor `jovian` and `sddm` modules for better composability.
Include `disko`, `sops`, `users`, `networking`, `pipewire`, `xdg` modules.
Enable `zsh`, `openssh`, `rtkit`, and add `git`, `neovim`, `htop`.
Renames the 'steam' system to 'deck' in flake.nix and sets up the
initial NixOS profile for the Steam Deck. This includes disk
partitioning with disko, a basic hardware configuration, and
enables the Jovian module for Steam Deck specific optimizations.
The previous 'profiles/steam' configuration has been removed.
Introduces a dedicated NixOS system profile for Steam, integrating Jovian-NixOS for Gamescope.
This includes:
- New 'jovian' flake input and module.
- New 'steam' profile using 'jovian' as a specialisation.
- Opens port 8050 in the tower firewall.
- Sets Alacritty to open maximized in Niri.
Integrates the discord bot as a new NixOS service.
This includes adding the flake input, configuring the service,
and setting up its environment variables via sops.
Enable the hermes-agent NixOS module and service.
Configure PostgreSQL database and user for Hermes.
Set up Anthropic model integration with dependencies and API URL.
Add hermes_env secret for agent environment variables.
Restructure AdGuard Home settings by nesting DNS-related options under a `dns` key.
Add `mutableSettings = false` for better NixOS management.
Update upstream and bootstrap DNS servers to Cloudflare and Quad9.
Adjust system nameservers for testing.
Adjusts the generated config file to use the `[api]` section and `key` field.
Adds `umask 077` for stricter file permissions and a check for secret readability.
Set `WorkingDirectory` for the backtest service.
Remove `STREAMLIT_BROWSER_GATHER_USAGE_STATS` env var from backtest.
Change `option-pricer` service port to 8503.
Adds home-manager modules for backtest, option-pricer, and portfolio-optimizer.
Each module configures the respective Streamlit dashboard as a systemd user service.
Move shared system modules and settings from host-specific
configurations into `profiles/common/default.nix`.
Rename `profiles/laptop/packages.nix` and `profiles/laptop/user.nix`
to `profiles/common/packages.nix` and `profiles/common/user.nix`.
Simplify host-specific configurations and extract root user's
home-manager setup to `users/root/default.nix`.
Introduce `mkPWA` function to simplify creating Progressive Web App
desktop items using `firefoxpwa`.
Also adds `browser.tabs.unloadOnLowMemory` and
`browser.ctrlTab.sortByRecentlyUsed` preferences.
Adds a dedicated Home Manager configuration for user 'marc' on the 'tower' host, integrating various modules like nixvim, niri, and sops.
Also reorders the 'tower' system definition for better organization.
Adds `--option download-buffer-size` to `nixos-install` for more reliable package downloads.
Simplifies and translates comments from French to English for better clarity.
Automates the initial NixOS setup, including disk partitioning with disko, hardware config generation, and installation.
Increases /tmp and /run/nixos buffer size to prevent "No space left on device" errors during flake evaluation.
The bar's `:exclusive` property is now set to `false`, allowing other windows to utilize the full screen height without being pushed down.
Increased bar height and horizontal padding to improve visual integration with this new behavior.
Integrates the ironbar status bar with a comprehensive configuration,
custom styling for a hover-to-show effect, and a systemd user service
for automatic startup.
Introduce a new Home Manager module for ytui-music, including its
configuration and a wrapper script. Also adds Spotube (Flatpak),
ytermusic, ncspot, and spotify-player to user packages.
The `install` recipe now accepts a `device` argument for `disko` and
includes the `nixos-install` step to complete the system setup.
A new `ventoy` recipe is added to prepare a Ventoy USB drive, install
Nix, and configure the disk using `disko`.
Introduce a dedicated `laptop-iso` NixOS configuration in `flake.nix` for building a bootable ISO image. The `Justfile` is updated to target this new configuration, and `*.iso` is added to `.gitignore`. Also adds `vm.overcommit_memory` to the ISO module.
Configure qBittorrent WebUI to use a subnet whitelist for authentication,
allowing access from localhost without requiring a password.
The hardcoded PBKDF2 password has been commented out.
Introduces the tewi text-based torrent client.
Defines its Nix package, including the geoip2fast dependency,
and integrates it into the home-manager configuration for user marc.
Switches to NetworkManager's 'ensureProfiles' for Wi-Fi configuration.
Generates a single .env file with all Wi-Fi PSKs, which NetworkManager reads.
This simplifies configuration and removes custom UUID generation.
Updates the 'sanitize' function to replace dots in SSIDs, requiring a secret name change.
Refreshes all flake inputs to their latest versions.
Introduces the rqbit torrent client as a new system service.
Temporarily disables catppuccin and clawdbot modules in flake.nix.
Switch from `overrideAttrs` to `pkgs.rustPlatform.buildRustPackage` for building `deep-filter-cli`. This provides a more idiomatic and robust way to package Rust applications in Nix, including proper `cargoHash` handling.
Provides a home-manager module for `deep-filter-cli`.
Overrides `deepfilternet` to disable failing tests and add
required build inputs for `hdf5` and `alsa-lib`.
Configure Zathura with PDF (Poppler, MuPDF) and PostScript plugins.
Enable recoloring with hue preservation.
Add deepfilternet and pdfarranger to user's home packages.
Remove zathura from direct home packages as it's now managed
via its dedicated module.
Introduces a new Home Manager module for `watt-monitor`.
This module builds the Rust application, adds it to the user's packages,
and configures a systemd user service to run it as a background daemon.
Adds playwright to both python and cli packages.
Overrides weasel in python environment to skip runtime dependency checks.
Removes typer, piper, your_spotify, and kokoro packages.
Add a Python environment with common data science libraries (numpy, pandas, matplotlib, scipy, scikit-learn, jupyterlab, ipython, requests, pillow) and edge-tts.
Introduces a 'getSecretName' helper for consistent naming of Wi-Fi
secrets and NetworkManager connection files. Updates existing
network definitions to use this new scheme.
Removes redundant 'wireless.iwd' configuration.
Adds "Wifi de Marc 2.4G" to the list of managed networks.
BREAKING CHANGE: Wi-Fi secret names have changed for some networks
(e.g., 'wifi_de_marc' is now 'wifi_wifi_de_marc'). Existing secrets
in 'secrets/laptop.yml' must be updated to reflect the new convention.
Define Wi-Fi networks in a list to automatically generate NetworkManager
connection profiles and sops secret placeholders. This simplifies
managing multiple Wi-Fi networks and their credentials.
Explicitly configure Catppuccin GTK theme with rimless and black tweaks.
Extend Catppuccin theming to Zathura and Spotify Player.
Integrate Catppuccin themes for LibreOffice and update VCL plugin to GTK4.
Add `gnome-themes-extra`, `arc-theme`, and `dracula-theme` packages.
Include a desktop entry for LibreOffice Calc with Dracula theme.
Integrates the `spicetify-nix` flake for Spotify customization.
Enables extensions like adblockify, hidePodcasts, and shuffle.
Sets the defaultDynamic theme and removes the old `spotify-adblock` package.
Adds home-manager setup for the root user, importing modules for Neovim, Zsh, Git, SSH, and GitHub CLI.
Also adds `bat` and `exa` to `environment.systemPackages`.
Adds a new age key for the laptop to `.sops.yaml` and re-encrypts secrets.
Configures Nextcloud to retrieve credentials via SOPS and use a PostgreSQL Unix socket.
Removes Minio object storage configuration from Nextcloud.
Temporarily disables the dnscrypt service.
Introduces `anywhere.yml` and `laptop.yml` containing encrypted credentials for services like Stalwart, Nextcloud, WiFi, and Vaultwarden.
These secrets are managed using SOPS with Age encryption.
Integrates the `clawdbot/nix-clawdbot` flake as a new input.
This includes its overlay for packages and its home-manager module
for user configurations.
Implement a dynamic scrolling text ticker in the center of the Eww bar.
This includes new SCSS for animation and fading effects, and Yuck updates
to integrate the ticker content and layout. Also renames some classes.
This module integrates the playsched application, a Spotify playlist scheduler.
It provides `playsched-web` for the web interface and `playsched-cli` for command-line control, along with all required Python dependencies.
Configure IPython to use vi keybindings in the terminal.
This creates `ipython_config.py` to set `editing_mode = 'vi'` and
`emacs_bindings_in_vi_insert_mode = False`.
Also removes unused `config` and `pkgs` module arguments.
Adds a desktop entry for Electron Mail with Wayland and dark mode flags.
Configures Niri to prefer no client-side decorations.
Removes commented-out xdg.portal configuration.
set Niri's xdg-portal default to 'gtk' and disable generic portal config.
add `ADW_DISABLE_PORTAL` and `SAL_USE_VCLPLUGIN` for improved GTK app behavior.
enable Beeper desktop entry and clean up unused comments.
Move imports block to top level for better module organization.
Remove unused `selectOpts` variable.
Fix missing closing brace for the `plugins` block.
Introduce nvim-cmp for completion, nvim-lspconfig for LSP, and conform.nvim for formatting.
Refactor existing UI plugins (lualine, neo-tree, onedark) into plugins/ui.nix for better organization.
Enable avante plugin.
Configures the `clipcat` service for clipboard history and a `clip-notify` service to show notifications on copy events.
Also sets `EDITOR` and `VISUAL` environment variables to `nvim`.
Marc Partensky's NixOS + Home Manager + nix-darwin configuration, one flake for every machine: `tower`, `laptop`, `deck`, the `anywhere` VPS, the Mac, and the phone (nix-on-droid).
| `nixosConfigurations.dev` | NixOS (microvm) | Disposable dev VM, see `vms/`. Launched with `just vm`. |
| `homeConfigurations.marc` | Home Manager standalone | Marc's Linux profile (tower/laptop), **not wired** into any `nixosConfigurations` — managed independently. |
| `homeConfigurations."marc@macos"` | Home Manager | HM profile on the Mac (on top of nix-darwin). |
| `homeConfigurations."marc@deck"` | Home Manager | HM profile on the Deck. |
| `darwinConfigurations.macos` | nix-darwin | The Mac's system config. |
Updating inputs: `nix flake update` before a rebuild (`--upgrade` has no effect on a flake, don't use it).
Eval check without building: `nix eval .#nixosConfigurations.$HOST.config.system.build.toplevel.drvPath --impure`.
## Secrets (sops-nix)
-`secrets/*.yml`, one file per domain (`tower.yml`, `common.yml`, `anywhere.yml`, `zitadel.yml`, `gitea.yml`, ...), encrypted with `sops` + `age` keys.
- 4 keys in `.sops.yaml`: anywhere, tower, mac, deck. `common.yml` is decryptable by every machine; each profile sets `sops.defaultSopsFile` to its dedicated file.
- Creating a **new** secret only needs the public keys already in `.sops.yaml`: `nix run nixpkgs#sops -- -e --filename-override secrets/<name>.yml --output secrets/<name>.yml <plaintext>`. Editing an **existing** file in place requires the private key (root only).
## Self-hosted services (tower/laptop)
Registry in `services/default.nix`. Active on tower:
- **Disabled in the registry** (commented out, pending a fix or waiting on something): `dnscrypt`, `minio`, `stalwart-mcp` (cargoHash mismatch), `gotify`, `kanidm`, `syncserver`, `matrix-telegram` (waiting on api_id/api_hash), `vaultwarden-mcp` (missing input).
## Conventions
- Comments and commit messages in French, conventional commits format (`feat(scope): ...`, `fix(scope): ...`, `chore(scope): ...`), grouped by logical theme (not one commit per touched file).
- A module is "enabled" by being added to its registry's import list (`services/default.nix`, `profiles/common/default.nix`, `users/marc/home.nix`, ...); commented out = disabled but kept as reference.
-`home-manager.users.marc` must **never** be wired into any `nixosConfigurations`: Marc's profile stays standalone Home Manager (`just home`), only `root` goes through the NixOS module (`profiles/common`).
- The repo is edited concurrently (multiple sessions/agents): check `git status` and that no `nixos-rebuild` is already running before triggering a switch.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.