Files
nas-runbooks/common/PROTOCOL-INFRA.md
T

14 KiB

PROTOCOL-INFRA — Regles operationnelles infra

Protocole post-deployement (OBLIGATOIRE)

Apres tout deployement reussi ou probleme resolu, avant de cloturer la mission :

  1. Creer un runbook dans le repo Gitea bolbol/nas-runbooks

    • Ecrire UNIQUEMENT dans le dossier hermes-[identite]/
    • Utiliser le template /opt/data/RUNBOOK-TEMPLATE.md
    • La section "Ce qui NE fonctionne PAS" est OBLIGATOIRE
  2. Poster une note NyoraNotes

    • Tags : [infra, runbook]
    • Contenu : resume du probleme, solution, lien runbook Gitea
  3. Mettre a jour _INDEX.md dans nas-runbooks

    • Ajouter l entree dans le tableau de l instance
  4. git add . && git commit && git push vers Gitea

Regle de contribution

  • Ecriture : chaque instance ecrit UNIQUEMENT dans son dossier hermes-[nom]/
  • Lecture : tous les dossiers sont accessibles en lecture
  • Le runbook sans les echecs n a pas de valeur — toujours documenter les tentatives infructueuses

Acces Gitea nas-runbooks

URL clone : http://192.168.100.33:3232/bolbol/nas-runbooks.git Dossier local suggere : /opt/data/workspace/nas-runbooks/


REGISTRE DES SERVICES — Mise a jour obligatoire

Le fichier /volume1/docker/ports-registry.md est la source de verite de l'etat du NAS. Il contient deux sections distinctes a maintenir en permanence :

1. SERVICES ACTIFS (en tete du fichier)

Mise a jour OBLIGATOIRE a chaque installation OU desinstallation :

  • Installation : ajouter la ligne avec statut ACTIF, port, domaine, notes
  • Desinstallation : changer le statut en "DESINSTALLE JJ/MM/AAAA", liberer le port
  • Ne JAMAIS supprimer une ligne — les services desinstalles restent visibles avec leur date

2. Historique des modifications (fin du fichier)

Ajouter une ligne datee pour CHAQUE action :

  • Format : | AAAA-MM-JJ | ACTION | Port | Service |
  • Actions a documenter : Deploiement, DESINSTALLATION, Migration, Changement de port

Verification avant documentation

Avant de marquer un service comme DESINSTALLE, TOUJOURS verifier : curl --max-time 4 http://172.17.0.1: -o /dev/null -w "HTTP %{http_code}" Si le port repond → le service est encore actif → NE PAS marquer DESINSTALLE

Chemin du fichier

  • Copie locale NAS : /volume1/docker/ports-registry.md
  • Copie nas-runbooks : /volume1/docker/nas-runbooks/common/ports-registry.md
  • Les deux doivent rester synchronisees (copier l'un vers l'autre apres modification)
  • Push Gitea obligatoire apres toute modification

Skills transverses — deploiement automatique sur les 3 instances

Quand une lecon apprise doit etre appliquee automatiquement par l agent (pas juste documentee pour lecture humaine), la deployer comme skill actif plutot que de compter sur un rappel manuel a chaque fois :

  1. Creer data/skills//SKILL.md sur les 3 instances (hermes-tt, hermes-nyora, hermes-perso), avec un frontmatter description contenant les mots-cles qui doivent declencher le skill
  2. Supprimer le cache .skills_prompt_snapshot.json (racine data/ et data/.hermes/) sur les 3 instances pour forcer la regeneration de l index
  3. Redemarrer les 3 containers hermes-agent-* (via socket Docker /var/run/docker.sock depuis mcp-nas, ou Portainer)
  4. Documenter quand meme via le protocole standard (runbook common/, _INDEX.md, note NyoraNotes) — le skill rend la regle automatique, le runbook garde la tracabilite

Exemples deployes le 02/07/2026 : desactivation des skills concurrents a nyora-doc-api (docx/pdf/pptx/xlsx), et skill generation-contenu-volumineux (chunking obligatoire pour eviter la troncature DeepSeek V4 Flash sur les taches lourdes).


Verification obligatoire avant toute lecture/ecriture sur nas-runbooks depuis mcp-nas

Git est ABSENT du container mcp-nas (confirme le 02/07/2026). Toute ecriture sur bolbol/nas-runbooks depuis une session mcp-nas passe par l API Gitea (curl + token, PUT/POST /api/v1/repos/bolbol/nas-runbooks/contents/, avec le sha courant recupere par un GET prealable) — jamais par un dossier local suppose a jour.

Piege decouvert le 02/07/2026 : /mnt/docker/nas-runbooks etait un clone git reel mais sur branche locale master, alors que le remote n a qu une branche main. 14 commits locaux (15-23 juin, jamais pousses) contenaient du contenu reel absent du remote. Cause probable : le binaire git a disparu de mcp-nas avant l etape push. Fix applique : recuperation des 14 fichiers via l API vers main, _INDEX.md corrige, clone local renomme en nas-runbooks.STALE-clone-local-jamais-pousse-20260702 (conserve pour inspection, plus utilise comme source).

Regle : avant de lire ou modifier un fichier sous /mnt/docker/nas-runbooks (ou tout repo Gitea) depuis mcp-nas, verifier d abord via l API que le contenu local correspond au remote reel : GET /api/v1/repos/bolbol//branches GET /api/v1/repos/bolbol//contents/ Si un vrai clone git fonctionnel est necessaire (multi-fichiers, historique), le faire depuis le Mac ou git est present, chemin partage /Volumes/docker == /volume1/docker.

gstack (garrytan/gstack) — decision actee le 02/07/2026

Installation prevue sur le futur MacBook M5 Pro via Claude Code natif, PAS sur hermes-perso (mem_limit container 600m incompatible Chromium/Playwright, routing Sonnet/Opus incompatible regle DeepSeek exclusif Hermes, bug upstream #2015 AskUserQuestion/clarify non resolu sur --host hermes). Detail complet : common/GSTACK-EVALUATION-MACBOOK-VS-HERMES.md.

Piege .env vs docker-compose.yml — decouvert le 03/07/2026

Ajouter une variable au .env d un service NE SUFFIT PAS si le docker-compose.yml declare un bloc environment: qui whiteliste explicitement chaque variable transmise au container (cas d hermes-platform/docker-compose.yml). Une variable absente de ce bloc n atteint jamais le container meme si elle est correcte dans le .env.

Regle : pour toute nouvelle variable d integration (cle API, URL de service), toujours verifier ET modifier les deux fichiers :

  1. .env (definition de la valeur)
  2. docker-compose.yml, bloc environment: du/des service(s) concerne(s) (transmission de la valeur au container)

Verification post-fix : docker exec env | grep sur le container recree.

Cas reel : NYORA_DOC_API_KEY manquante des deux fichiers pour les 3 instances Hermes -> 401 sur nyora-doc-api. Detail complet : common/nyora-doc-api-hermes-guide.md, section "Panne corrigee le 03/07/2026".

RÈGLE CRITIQUE — Cron Hermes et publish n8n : une modif écrite sur disque n'est pas une modif live

Cron Hermes (jobs.json)

Le service cron de chaque agent Hermes (hermes-agent-tt / hermes-agent-nyora / hermes-agent-perso) charge jobs.json UNIQUEMENT au démarrage du container. Il ne relit jamais le fichier en cours de route. Modifier jobs.json (horaire, prompt, modèle) laisse le service tourner avec l'ancienne config en mémoire tant que le container n'est pas redémarré.

  • Après toute modification de jobs.json : redémarrer le container agent correspondant (nom réel : hermes-agent-tt / hermes-agent-nyora / hermes-agent-perso — PAS hermes-tt/hermes-nyora/hermes-perso, ce sont les containers hermes-workspace-*).
  • Restart via API Portainer : POST /api/endpoints/2/docker/containers/{id}/restart timeout systématiquement sur cette instance. Utiliser stop puis start explicites (2 appels), pas restart.
  • Après redémarrage, TOUJOURS vérifier next_run_at dans jobs.json correspond bien au nouveau schedule — sinon le corriger manuellement (le daemon ne recalcule pas toujours correctement au premier boot).
  • Portainer : endpoint local = id 2. Auth via 172.17.0.1:9000/api/auth (pas 192.168.100.33 depuis un container), credentials dans hermes-platform/.env.

Publish n8n (workflow actif modifié via l'outil update_workflow)

update_workflow sauvegarde un brouillon (nouveau versionId) mais n'active PAS automatiquement ce brouillon sur un workflow déjà publié — le workflow continue de servir l'ancienne activeVersion. publish_workflow peut échouer silencieusement avec "Version not found" sur un workflow dont la chaîne de versions est corrompue, y compris en réessayant depuis l'UI n8n elle-même (pas un bug de l'outil MCP).

  • Après toute modification d'un workflow n8n déjà actif : vérifier avec get_workflow_details que versionId == activeVersionId. Si différent, le changement n'est PAS en production.
  • Si publish_workflow échoue de façon persistante (même après unpublish_workflow puis republish) : ne pas insister, dupliquer le workflow (bouton Duplicate dans l'UI n8n) — la copie repart avec une chaîne de versions saine et se publie normalement. Archiver l'original cassé (archive_workflow) une fois la copie confirmée active.

Fuseau horaire

Le NAS et n8n tournent en UTC. Tunis = UTC+1 toute l'année (pas de changement d'heure). Pour un cron en heure de Tunis, toujours retirer 1h à l'expression cron (ex: 7h/12h/20h Tunis = "0 6,11,19 * * *" en UTC).

Leçon générale

Une réponse "success" d'un outil de modification (update_workflow, edit de jobs.json) ne garantit jamais que le changement est en production. Toujours vérifier l'état réel après coup : next_run_at recalculé pour un cron Hermes, activeVersion == draft pour un workflow n8n.

Git depuis mcp-nas — canal actuel (2026-07-10)

git n'est plus présent dans le container mcp-nas ni sur le NAS. Le canal standard pour toute écriture Gitea est l'API HTTP change-files :

  • Auth : GITEA_DEPLOY_TOKEN (scope write:repository, .env hermes-platform), header Authorization: token <TOK>. L'ancien password bolbol est périmé (401) — le runbook git-push-depuis-mcp-nas.md est obsolète sur ce point.
  • Endpoint : POST /api/v1/repos/bolbol/<repo>/contents avec files:[{operation:create|update, path, content(base64), [sha]}] → 1 commit multi-fichiers (Gitea 1.21.11).
  • Réseau : toujours 172.17.0.1:3232 depuis le container. Fichiers NAS lisibles/éditables via le mount /mnt/docker = /volume1/docker.
  • SSH Best0f par mot de passe : non fonctionnel depuis mcp-nas (pas de clé, SSHPASS ≠ mdp Best0f) — ne pas compter dessus.
  • Restart de containers sans docker CLI : API Portainer (creds bestof dans .env), POST /endpoints/{id}/docker/containers/{id}/restart.

2026-07-20 — Partition système /dev/md0 pleine (95%, 113 Mo restants) — résolu

Symptôme : df -h / sur l'hôte NAS à 95%. Piège : depuis le container mcp-nas, df -h / pointe sur /dev/mapper/cachedev_0 (volume data, 11 To) — toujours ssh nas-host pour voir la vraie partition système /dev/md0 (~2,3 Go, taille fixe DSM).

Méthode : du -sx / sans sudo (Best0f) sous-estime toujours l'usage réel — les dossiers root en permissions restrictives (souvent 0700) sont exclus silencieusement du total, pas juste illisibles en contenu. Comparer du -sx / 2>/dev/null au "Used" de df -h / ; un écart de plusieurs centaines de Mo pointe vers un dossier root oublié. Lister les coupables : du -sx / 2>&1 1>/dev/null | grep denied.

Cause ici : /usr/lib/python3.8/site-packages (0700 root:root) contenait une stack data-science/Streamlit complète (pandas, numpy, pyarrow, pillow, altair, jupyter) installée à la main début 2026 dans le Python système de base — pas un paquet Package Center, aucun process actif, aucun lien avec le stack actuel. Prototype abandonné.

Fix : sudo rm -rf /usr/lib/python3.8/site-packages/* /usr/etc/jupyter /usr/share/jupyter → 2,1 Go → 1,7 Go utilisés, 113 Mo → 529 Mo disponibles (95% → 77%). Diagnostic fait en lecture seule par Best0f (sans sudo), suppression exécutée par Nabil (le mot de passe sudo Best0f n'est jamais transmis à un agent). Runbook détaillé : common/partition-systeme-nas-du-vs-df-permissions.md.

REGLE CRITIQUE -- Anti-invention sur chiffres de recherche/benchmarks (2026-07-27)

Avant de presenter un chiffre (benchmark, prix, score) dans un rapport : le chiffre doit venir d'une page reellement lue en entier, pas d'un snippet de recherche. Si un fetch demande ne renvoie qu'une coquille vide (page JS, < 500 caracteres utiles) -> le dire explicitement, ne jamais compenser en silence par une recherche generique. Verifier le nom EXACT de la variante (Pro/Max/Flash/base) avant d'attribuer un chiffre -- deux benchmarks avec un score identique = signal d'hallucination a corriger avant envoi, jamais a ignorer. Detail complet : common/anti-hallucination-benchmarks-recherche-chiffree.md.

FIX -- auxiliary.vision mal route sur modeles text-only (2026-07-27)

auxiliary.vision.provider: auto resout vers le modele principal -- casse systematiquement sur deepseek-v4-flash (text-only). Toute instance avec un modele principal text-only DOIT router auxiliary.vision explicitement vers google/gemini-2.5-flash via bifrost-proxy (meme base_url/api_key que le modele principal). Applique sur hermes-perso et hermes-tt le 27/07/2026. Detail : common/vision-auxiliaire-routing-text-only-modeles.md.

FIX -- approvals.mode: smart + deny rules sur les 4 instances Hermes (2026-07-27)

Passage de manual/auto (valeur invalide sur tt) a smart sur hermes-perso, hermes-tt, hermes-nyora, hermes-nabil. cron_mode: deny inchange (un job planifie qui tombe sur une commande signalee reste bloque, jamais auto-approuve). Ajout de approvals.deny (patterns absolus, bloques avant meme le jugement du modele auxiliaire ou un /yolo) -- rm -rf /, dd vers /dev/, redirection vers .env/credentials/secrets, git push --force, docker volume rm/system prune, DROP TABLE/DATABASE ; + TRUNCATE et DELETE Baserow en plus sur hermes-tt. auxiliary.approval route explicitement vers deepseek-v4-flash (jamais mimo-v2.5, meme quand c'est le modele principal de l'instance) -- le juge de securite doit etre le modele le plus fiable des deux, pas le defaut. Exception : hermes-nabil (VPS) n'a aucune route deepseek disponible, laisse en auto (mimo-v2.5), ecart documente. Detail : common/smart-approvals-deny-rules-4-instances.md.