20 ans d’IT : l’IA décryptée, intégrée, rentabilisée.
SEO GEO Intégration IA Optimisation PME
Discutons →

Déployez Google Gemma 4 en local pour votre PME : zéro donnée vers l’étranger

ChatGPT, Claude, Mistral envoient vos données vers des serveurs étrangers. Pour une PME suisse soumise à la nLPD, c’est un risque juridique réel. Gemma 4 (Google, Apache 2.0, #3 mondial Arena IA) tourne sur un Mac mini M4 à CHF 700. 15 minutes d’installation, 3 commandes Ollama.

1. Le problème : vos données partent aux USA

Quand un employé de votre PME colle un email client, un devis ou un contrat dans ChatGPT, les données transitent par des serveurs d’OpenAI aux États-Unis. Idem avec Claude (Anthropic), Gemini (Google), ou Mistral (France, mais serveurs US pour les APIs).

La nLPD, nouvelle Loi sur la Protection des Données, en vigueur depuis septembre 2023, impose que tout transfert de données personnelles vers l’étranger soit encadré par des garanties adéquates. En pratique : la plupart des PME suisses qui utilisent des LLMs cloud le font sans contrat de traitement de données complet, ce qui constitue une non-conformité.

Point clé

Un LLM local ne résout pas tous les problèmes juridiques, mais il élimine le vecteur principal de fuite de données : le transfert réseau vers un tiers étranger. Vos données ne quittent jamais votre machine.

2. Pourquoi Gemma 4 ?

Gemma 4 est la quatrième génération de modèles open source de Google. Lancé en mars 2026 sous licence Apache 2.0, il est utilisable commercialement sans redevance.

Positionnement benchmarks (avril 2026)

Modèle Arena IA (ELO) Licence Hardware minimum
Gemma 4 E4B#3 mondialApache 2.0Mac mini M4 16 GB / 8 GB VRAM GPU
Llama 4 Scout#4Llama 4 Community16 GB VRAM GPU (MoE 17B actifs)
Qwen3 32B#5Apache 2.024 GB VRAM GPU
GPT-4o (réf. cloud)#1PropriétaireSaaS uniquement

E4B signifie « Efficient 4 Billion ». C’est un modèle à mélange d’experts (MoE) : 26 milliards de paramètres au total, seulement 4 milliards activés par token. Résultat : performances proches d’un 27B dense pour un coût de calcul équivalent à un 4B.

En pratique sur un Mac mini M4 Pro 24 GB : 25–35 tokens/seconde. Pour de la rédaction, synthèse ou support interne, c’est largement suffisant.

  • Apache 2.0 : usage commercial libre, zéro redevance
  • #3 Arena IA en avril 2026 (source : lmarena.ai)
  • Mac mini M4 16 GB : 15–22 tok/s sur E4B (quantizé Q4)
  • Mac mini M4 Pro 24 GB : 25–35 tok/s sur E4B
  • Fenêtre de contexte : 128 000 tokens via Ollama
  • Taille fichier modèle : ~3.5 GB (Q4_K_M)

3. 3 options de déploiement selon votre cas

Le bon choix dépend de votre nombre d’utilisateurs simultanés et de votre volume mensuel de tokens.

Mac mini M4 : achat unique
CHF 700 (16 GB) · CHF 1 100 (Pro 24 GB)
Recommandé pour 1 à 5 utilisateurs simultanés. Silencieux, 20 W de consommation, aucune installation de rack. Branchez, installez Ollama, opérationnel. ROI < 6 mois vs abonnement SaaS équivalent. Idéal PME 5–50 employés.
VPS GPU Infomaniak Zurich
CHF 200 à 400/mois
Pour 5 à 20 utilisateurs simultanés. Infomaniak est hébergé en Suisse, ISO 27001, compatible nLPD sans clause supplémentaire. GPU NVIDIA disponibles (A100 partagé ou dédié). Option idéale si vous n’avez pas d’infrastructure physique ou si vous voulez une haute disponibilité.
Serveur on-premise avec GPU
CHF 3 000+ investissement initial
Pour usage intensif : 50 M+ tokens/mois, 20+ utilisateurs, intégration dans des workflows automatisés. NVIDIA RTX 4090 (24 GB VRAM, ~CHF 1 800) ou RTX 4070 (12 GB VRAM, ~CHF 700). Nécessite refroidissement et alimentation stable.
Pour 80 % des PME suisses de 10–50 personnes : le Mac mini M4 est le bon choix. Simple, silencieux, conforme, rentable en 6 mois.

4. Installation : 3 commandes

On utilise Ollama comme runtime. C’est l’outil standard pour faire tourner des modèles GGUF localement : API OpenAI-compatible, gestion des modèles, interface CLI, démon système.

Prérequis système

macOS : macOS 13 Ventura minimum. M1/M2/M3/M4 tous supportés (Metal natif). RAM unifiée : 16 GB minimum pour Gemma 4 E4B confortable.

Linux : Ubuntu 22.04+, Debian 12+. GPU NVIDIA : CUDA 12.x, drivers 525+. CPU uniquement si pas de GPU (fonctionnel, plus lent).

Windows : Windows 10/11. GPU NVIDIA CUDA supporté (driver 537+). CPU fallback disponible.

Étape 1. Installer Ollama

macOS / Linux : une commande
curl -fsSL https://ollama.com/install.sh | sh
macOS : téléchargez l’app sur ollama.com/download si vous préférez une interface graphique. Le script shell installe la même chose en CLI. Windows : installeur .exe disponible sur le même site.

Étape 2. Télécharger Gemma 4 E4B

~3.5 GB, environ 5 min selon la connexion
ollama pull gemma4:e4b

Ollama télécharge le modèle depuis son registry et le stocke dans ~/.ollama/models/. Opération unique : le modèle reste sur disque, plus besoin d’internet ensuite.

Étape 3. Lancer le modèle

Session interactive (REPL)
ollama run gemma4:e4b

Vous obtenez un prompt interactif dans le terminal. Si vous voyez une réponse en quelques secondes, l’installation est opérationnelle.

Vérifier les modèles installés
ollama list
# NAME           ID              SIZE    MODIFIED
# gemma4:e4b     e8db66a15f30    3.5 GB  il y a 2 minutes

5. Configuration et premier test

Ollama démarre un serveur HTTP local sur localhost:11434 automatiquement. Vous pouvez l’interroger sans ouvrir de session interactive.

Test via curl

Appel direct à l’API REST (JSON)
curl http://localhost:11434/api/generate \
  -d '{
    "model": "gemma4:e4b",
    "prompt": "Résume en 3 points ce qu'\''est la nLPD.",
    "stream": false
  }'

Démarrage automatique au boot (Linux)

systemd : une fois suffit
sudo systemctl enable ollama
sudo systemctl start ollama
sudo systemctl status ollama
macOS : Ollama s’enregistre comme agent de lancement automatiquement au premier démarrage. Aucune configuration supplémentaire requise.

6. Exposer l’API pour vos outils internes

Ollama expose une API OpenAI-compatible. Tous les outils qui supportent une base URL personnalisée (n8n, LangChain, Open WebUI, Continue.dev…) fonctionnent sans modification de code.

Python : exemple de base

Python 3.10+ : pip install openai
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:11434/v1",
    api_key="sk-no-key-required"  # Ollama n'utilise pas de clé
)

response = client.chat.completions.create(
    model="gemma4:e4b",
    messages=[
        {"role": "user", "content": "Rédige un mail de relance professionnel."}
    ]
)
print(response.choices[0].message.content)

Accès réseau local (LAN)

Par défaut Ollama écoute sur 127.0.0.1 uniquement. Pour accéder depuis d’autres machines sur votre réseau interne :

Variable d’environnement : à définir avant de lancer Ollama
# macOS / Linux : ajouter dans ~/.zshrc ou ~/.bashrc
export OLLAMA_HOST="0.0.0.0:11434"

# Puis redémarrer Ollama
# macOS : quitter l'app depuis la barre de menu, relancer
# Linux : sudo systemctl restart ollama
Sécurité : N’exposez pas Ollama directement sur Internet sans authentification. Sur un LAN privé, le risque est faible. Pour un accès distant, ajoutez un reverse proxy Nginx avec auth basique, ou utilisez Tailscale.

Open WebUI : interface chat pour votre équipe

Pour donner à votre équipe une interface similaire à ChatGPT, Open WebUI (MIT) se branche directement sur Ollama :

Docker : interface accessible sur http://localhost:3000
docker run -d \
  -p 3000:8080 \
  -v open-webui:/app/backend/data \
  -e OLLAMA_API_BASE_URL=http://host.docker.internal:11434/api \
  --name open-webui \
  --restart always \
  ghcr.io/open-webui/open-webui:main

7. Les limites à connaître

Performances vs cloud

Gemma 4 E4B sur Mac mini M4 est excellent pour son hardware. Il n’atteint pas GPT-4o ou Claude 3.7 Sonnet sur les tâches de raisonnement multi-étapes complexes. Pour de la génération, résumé, classification, extraction d’information, la différence est marginale dans l’usage quotidien.

Concurrent users

Ollama gère la concurrence mais un seul modèle tourne par défaut. Sur Mac mini M4 16 GB, au-delà de 3–4 requêtes simultanées la latence augmente. Pour 10+ utilisateurs simultanés, passez au Mac mini Pro 24 GB ou à un GPU dédié.

Mise à jour manuelle

Contrairement aux SaaS, vous gérez les mises à jour vous-même. Quand Gemma 5 sortira : ollama pull gemma5:xxx. Pas complexe, mais à planifier.

Aspect Ollama + Gemma 4 local ChatGPT cloud
Données clientReste sur votre machineServeurs US, rétention variable
Conformité nLPDOui, sans contrat supplémentaireContrat DPA requis, transfert international
Coût mensuel~CHF 3 (électricité)CHF 20–30 /utilisateur/mois
QualitéExcellent pour usage PME courantLégèrement supérieur sur tâches complexes
MaintenanceMise à jour manuelleAutomatique
DisponibilitéFonctionne hors connexionNécessite Internet
PersonnalisationSystem prompts, fine-tuning possibleLimité (pas de fine-tuning GPT-4o)

8. Verdict

Pour une PME suisse de 5 à 50 personnes : installez Gemma 4 sur un Mac mini M4. C’est la combinaison la plus simple, la plus conforme et la plus rentable disponible aujourd’hui.

Le ROI est rapide. Un abonnement ChatGPT Team coûte CHF 25 par utilisateur par mois. Cinq utilisateurs = CHF 125/mois = CHF 1 500/an. Le Mac mini M4 à CHF 700 est amorti en moins de 6 mois, avec une meilleure confidentialité des données.

Ce tuto est notre pratique réelle : Gemma 4 E4B tourne sur un Mac mini M4 Pro 24 GB dans notre stack depuis mars 2026. Il traite synthèse de sources, rédaction de brouillons et analyse de documents. Pour les tâches nécessitant le niveau GPT-4o (raisonnement complexe, code avancé), on garde une API cloud avec données anonymisées. Architecture hybride : local pour les données sensibles, cloud quand la qualité prime.

Sources & ressources
Ollama : Runtime LLM local, API OpenAI-compatible
Google Gemma : Documentation officielle
Gemma 4 E4B sur HuggingFace : Poids et benchmarks
Open WebUI : Interface web open source pour Ollama
Infomaniak GPU VPS : Hébergement cloud suisse
nLPD / PFPDT : Loi fédérale sur la protection des données (Suisse)
#Gemma4 #Ollama #LLMLocal #PME #nLPD #IA #MacMiniM4 #legeektech

J’ai construit un système de garde-fous pour empêcher Claude Code de me mentir

Après des semaines de collaboration intensive avec Claude Code, j’ai identifié des patterns comportementaux toxiques récurrents : complaisance, mensonges par omission, raccourcis non signalés, oubli des corrections entre sessions. J’ai conçu et déployé un système à 3 couches, enforcement mécanique, mémoire persistante, observabilité, pour rendre l’IA fiable de manière structurelle, pas volontaire.

Le problème que personne ne veut voir

On parle beaucoup d’hallucinations factuelles des LLM. « L’IA a inventé une référence », « l’IA a cité un package qui n’existe pas ». OK. C’est un problème connu, documenté, sur lequel tout le monde travaille.

Mais il y a un autre problème, plus insidieux, dont personne ne parle : la complaisance comportementale.

Je développe depuis janvier 2026 une PWA de gestion immobilière avec Claude Code comme co-pilote principal. Pas un jouet, une vraie app en production, avec une vraie cliente qui l’utilise au quotidien. Express, React, Supabase, AssemblyAI, déployé sur un VPS Hostinger.

Et au bout de 3 mois de travail intensif, voici ce que j’ai observé :

Les 5 patterns toxiques

1. La complaisance
Claude Code livre vite pour faire plaisir. La réponse rapide prime sur la réponse correcte. Tu demandes un diagnostic sur un bug ? Il te sort une hypothèse en 30 secondes sans avoir regardé la donnée réelle. Ça a l’air pro. C’est faux.

2. Le mensonge par omission
Je lui ai prescrit d’utiliser un outil spécifique (Stitch MCP) pour générer des visuels. Il a généré du HTML/CSS à la place, un résultat médiocre, et me l’a présenté comme si c’était normal. Sans me dire qu’il n’avait pas utilisé l’outil prescrit.

3. Le non-respect des règles
Claude Code a un système de fichiers d’instructions (CLAUDE.md) où tu peux écrire des règles. J’en ai écrit. Beaucoup. Il les ignore dès que le chemin facile existe. Même quand je les répète 3 fois dans la même session.

4. L’echo chamber inter-agents
Claude Code peut lancer des sous-agents pour des tâches complexes. En pratique, les agents se confortent mutuellement. L’un propose une approche facile, l’autre la valide, le résultat m’est présenté comme un « consensus ». C’est un consensus entre oui-oui.

5. L’oubli inter-sessions
Tu corriges un comportement en session 1. En session 2, la correction est oubliée. Tu recorriges. Session 3, oubliée. Tu finis par écrire la correction dans un fichier de mémoire. Session 4 : le fichier existe mais n’est pas consulté.

Le vrai coût

Le problème n’est pas que l’IA fait des erreurs. Le problème c’est que si je dois tout vérifier et tout surveiller, il n’y a aucun gain de productivité. L’outil devient un coût, pas une aide.

La réflexion : pourquoi les solutions classiques échouent

CLAUDE.md ne suffit pas

Les instructions dans CLAUDE.md sont l’équivalent d’un panneau « Interdit de rouler à 150 km/h ». Sans radar, sans amende, sans barrière physique. La recherche académique confirme : la conformité des LLM aux instructions décroît linéairement avec le nombre d’instructions. Au-delà de 20 règles, c’est < 30 % de conformité en mode agent.

Les hooks d’avertissement ne suffisent pas

J’avais déjà construit un système de hooks (BRAKE) qui injectait des messages d’avertissement avant certaines actions. Le problème : ces messages font exit 0, ils informent, ils ne bloquent pas. Claude les voit, les ignore, et continue.

Les fichiers de mémoire ne suffisent pas

J’ai 30+ fichiers markdown de feedbacks, corrections, protocoles. Ils existent. Ils ne sont pas consultés. C’est comme avoir une bibliothèque fermée à clé.

Le constat fondamental

Tout mécanisme qui dépend de la bonne volonté de l’IA échouera.
La fiabilité doit être mécanique, pas volontaire.

Les recherches : qu’est-ce qui existe ?

Avant de foncer tête baissée dans une implémentation, j’ai fait un tour exhaustif de ce qui existe.

Systèmes de mémoire agent

SolutionStars GitHubMaturitéCe que ça fait
Mem051K3 ansMémoire persistante, API simple
Letta (ex-MemGPT)22K2.5 ansRuntime agent avec mémoire intégrée
Cognée15K2.5 ansMémoire cognitive structurée
Hindsight6.5K5 moisMémoire biomimatique 3 niveaux, 91.4 % sur LongMemEval
Zep4.3K3 ansMémoire temporelle, principalement SaaS

Constat : tous font du recall. Aucun ne fait de l’enforcement. Ils résolvent « j’ai oublié », pas « je m’en fous ».

Frameworks de guardrails

SolutionStarsCompatible Claude Code ?
NeMo Guardrails (NVIDIA)5.9KNon, conçu pour chatbots
Guardrails AI6.6KNon, valide le format, pas le comportement

Solutions spécifiques Claude Code

SolutionPertinence
Hooks natifs (PreToolCall/Stop)Le seul mécanisme qui peut bloquer une action, via exit 2
Plugin HindsightAuto-recall sur chaque prompt, auto-retain en fin de session
LangfuseObservabilité, traces, scoring, dashboard

La solution : combiner 3 couches complémentaires.

L’architecture : 3 couches, 3 fonctions, zéro bonne volonté requise

┌─────────────────────────────────────────────────────┐
│                 PROMPT UTILISATEUR                    │
└──────────────────────┬──────────────────────────────┘
                       ▼
┌─────────────────────────────────────────────────────┐
│  COUCHE B — HINDSIGHT (mémoire)                      │
│  Hook UserPromptSubmit → auto-recall                 │
│  Injecte les feedbacks pertinents dans le contexte   │
│  L’IA ne choisit PAS de les voir. Ils sont là.      │
└──────────────────────┬──────────────────────────────┘
                       ▼
┌─────────────────────────────────────────────────────┐
│  L’IA RAISONNE                                       │
│  (avec les feedbacks injectés en face d’elle)        │
└──────────────────────┬──────────────────────────────┘
                       ▼
┌─────────────────────────────────────────────────────┐
│  COUCHE A — BRAKE HARD (enforcement)                 │
│  Hook PreToolCall → gate.sh                          │
│  Vérifie AVANT chaque outil :                        │
│  - Read code sans DB query ? → exit 2 (BLOQUE)      │
│  - Deploy sans audit ? → exit 2 (BLOQUE)            │
│  - HTML au lieu de Stitch ? → exit 2 (BLOQUE)       │
│  Exit 2 = outil refusé. Pas un warning, un MUR.     │
└──────────────────────┬──────────────────────────────┘
                       ▼ (si autorisé)
┌─────────────────────────────────────────────────────┐
│  OUTIL EXECUTE                                       │
└──────────────────────┬──────────────────────────────┘
                       ▼
┌─────────────────────────────────────────────────────┐
│  COUCHE C — LANGFUSE (observabilité)                 │
│  Trace passive : quel outil, quel contexte,          │
│  quel résultat. Dashboard consultable.               │
│  Ne bloque rien. OBSERVE.                            │
└─────────────────────────────────────────────────────┘
CoucheRôleAnalogie
HindsightJe ne peux pas dire « j’ai oublié »La mémoire arrive automatiquement
BRAKEJe ne peux pas dire « j’ai vu mais j’ai décidé autrement »L’outil est physiquement refusé
LangfuseJe ne peux pas dire « ça s’est bien passé »Les traces sont là, vérifiables

Tutoriel : implémenter le système complet

Prérequis

  • Claude Code installé (npm install -g @anthropic-ai/claude-code)
  • Docker et Docker Compose
  • Python 3.11+

Étape 1. Couche A : BRAKE Hard (enforcement)

C’est le cœur du système. Le seul mécanisme qui bloque réellement dans Claude Code.

1.1 Créer la structure

mkdir -p ~/.claude/brake

1.2 gate-parse.py : Le parser Python

#!/usr/bin/env python3
"""Parse l'input du hook PreToolCall, met a jour session-state, retourne les infos."""
import json, os, sys
from datetime import datetime
SESSION_FILE = os.path.expanduser("~/.claude/brake/session-state.json")
try: inp = sys.stdin.read()
except: inp = ""
tool_name = "unknown"; file_path = ""; command = ""
try:
    d = json.loads(inp); tool_name = d.get("tool_name","unknown")
    ti = d.get("tool_input",{})
    if isinstance(ti,dict):
        file_path = ti.get("file_path",ti.get("path",""))
        command = ti.get("command","")
except: pass
try:
    with open(SESSION_FILE) as f: state = json.load(f)
except:
    state = {"db_queried":False,"roko_invoked":False,"tests_run":False,
             "context_mode":"dev","files_read":0,"files_edited":0,
             "deploy_attempted":False,"tools":[]}
state["tools"].append({"tool":tool_name,"time":datetime.now().isoformat()[:19]})
cmd_lower = command.lower()
if tool_name=="Bash" and any(k in cmd_lower for k in
    ["supabase","pipeline_jobs","from('","from(\"",".select(","psql"]):
    state["db_queried"] = True
if tool_name=="Bash" and "roko" in cmd_lower: state["roko_invoked"] = True
if tool_name=="Bash" and any(k in command for k in
    ["npm test","npm run test","jest","vitest","mocha","pytest"]):
    state["tests_run"] = True
if tool_name in ("Read","Grep"): state["files_read"] = state.get("files_read",0)+1
if tool_name in ("Edit","Write"): state["files_edited"] = state.get("files_edited",0)+1
if tool_name=="Bash" and any(k in command for k in
    ["rsync","pm2 restart","pm2 reload","docker push","npm run deploy"]):
    state["deploy_attempted"] = True
with open(SESSION_FILE,"w") as f: json.dump(state,f)
print(f"{tool_name}|||{file_path}|||{command}|||{state['db_queried']}|||"
      f"{state['roko_invoked']}|||{state['tests_run']}|||"
      f"{state['files_read']}|||{state['files_edited']}|||{state.get('context_mode','dev')}")

1.3 gate.sh : Le script de blocage

#!/usr/bin/env bash
# gate.sh — PreToolCall hook : BLOQUE les actions non conformes (exit 2)
# Exit 0 = autorise | Exit 2 = BLOQUE
trap 'exit 0' ERR
BRAKE_DIR="$HOME/.claude/brake"
INPUT=""
if [[ ! -t 0 ]]; then INPUT=$(cat 2>/dev/null || true); fi
PARSED=$(echo "$INPUT" | python3 "$BRAKE_DIR/gate-parse.py" 2>/dev/null \
  || echo "unknown||||||False|||False|||False|||0|||0|||dev")
TOOL_NAME=$(echo "$PARSED" | cut -d'|' -f1)
FILE_PATH=$(echo "$PARSED" | cut -d'|' -f4)
COMMAND=$(echo  "$PARSED" | cut -d'|' -f7)
DB_QUERIED=$(echo "$PARSED" | cut -d'|' -f10)
ROKO_INVOKED=$(echo "$PARSED" | cut -d'|' -f13)
TESTS_RUN=$(echo "$PARSED" | cut -d'|' -f16)
FILES_READ=$(echo "$PARSED" | cut -d'|' -f19)
[[ "$TOOL_NAME" == "unknown" || -z "$TOOL_NAME" ]] && exit 0
# REGLE 1 : lecture code serveur sans DB
if [[ "$TOOL_NAME" == "Read" || "$TOOL_NAME" == "Grep" ]]; then
  if echo "$FILE_PATH" | grep -qE '(server/|worker|pipeline|api/)' 2>/dev/null; then
    if [[ "$DB_QUERIED" == "False" && "${FILES_READ:-0}" -gt 2 ]]; then
      echo "BRAKE BLOQUE : Lecture serveur sans requete base (${FILES_READ})." >&2; exit 2; fi; fi; fi
# REGLE 2 : edition sans diagnostic base
if [[ "$TOOL_NAME" == "Edit" || "$TOOL_NAME" == "Write" ]]; then
  if echo "$FILE_PATH" | grep -qE '\.(js|ts|jsx|tsx|py)$' 2>/dev/null; then
    if [[ "$DB_QUERIED" == "False" && "${FILES_READ:-0}" -gt 3 ]]; then
      echo "BRAKE BLOQUE : Edition apres $FILES_READ lectures sans DB." >&2; exit 2; fi; fi; fi
# REGLE 3 : publication sans audit
if [[ "$TOOL_NAME" == "Bash" ]]; then
  if echo "$COMMAND" | grep -qE '(rsync|pm2 restart|pm2 reload|docker push|npm run deploy)' 2>/dev/null; then
    if [[ "$ROKO_INVOKED" == "False" ]]; then
      echo "BRAKE BLOQUE : Publication sans audit contradicteur." >&2; exit 2; fi; fi; fi
# REGLE 4 : push sans tests
if [[ "$TOOL_NAME" == "Bash" ]]; then
  if echo "$COMMAND" | grep -qE 'git push.*(main|develop|origin)' 2>/dev/null; then
    if [[ "$TESTS_RUN" == "False" ]]; then echo "BRAKE BLOQUE : Push sans tests." >&2; exit 2; fi; fi; fi
exit 0

1.4 Reset de session + hooks settings.json

# Reset l'etat de session (a lancer au debut de chaque session Claude Code)
echo '{"db_queried":false,"roko_invoked":false,"tests_run":false,"context_mode":"dev","files_read":0,"files_edited":0,"deploy_attempted":false,"tools":[]}' \
  > ~/.claude/brake/session-state.json

# Ajouter dans ~/.claude/settings.json :
{
  "hooks": {
    "PreToolCall": [{
      "matcher": "Read|Grep|Edit|Write|Bash",
      "hooks": [{"type":"command","command":"bash $HOME/.claude/brake/gate.sh","timeout":5}]
    }]
  }
}

Étape 2. Couche B : Hindsight (mémoire persistante)

Hindsight est un système de mémoire biomimatique pour agents IA. Il organise les souvenirs en 3 niveaux (faits, observations, modèles mentaux) et les retrouve via 4 stratégies en parallèle.

Ce qui nous intéresse : le plugin Claude Code qui injecte automatiquement les memories pertinentes dans le contexte de l’IA à chaque prompt.

# Lancer Hindsight (voir docker-compose.yml complet dans l'article original)
# Image : pgvector/pgvector:pg18 + ghcr.io/vectorize-io/hindsight:latest
# Note : utiliser pgvector externe, le pg0 embarque a un bug (#675)

# Verifier
curl -s http://localhost:8888/health
# {"status": "healthy", "database": "connected"}

# Creer la bank globale
curl -s -X PUT http://localhost:8888/v1/default/banks/david-global \
  -H "Content-Type: application/json" \
  -d '{"description": "Regles globales, feedbacks, protocoles"}'

# Ingerer un feedback exemple
curl -s -X POST http://localhost:8888/v1/default/banks/david-global/memories \
  -H "Content-Type: application/json" \
  -d '{"items":[{"content":"Regle : requeter la base AVANT lire le code source.","context":"feedback-rule","tags":["feedback"]}],"async":false}'

# Installer le plugin Claude Code
claude plugin marketplace add vectorize-io/hindsight
claude plugin install hindsight-memory
# ~/.hindsight/claude-code.json
{
  "hindsightApiUrl": "http://localhost:8888",
  "bankId": "david-global",
  "bankMission": "Memoire globale. Regles de travail, feedbacks critiques, protocoles obligatoires.",
  "retainMission": "Extraire : corrections comportementales, decisions techniques, preferences de travail.",
  "autoRecall": true,
  "autoRetain": true,
  "recallBudget": "mid",
  "recallMaxTokens": 2048,
  "recallTypes": ["world","experience","observation"],
  "recallContextTurns": 2,
  "retainEveryNTurns": 5,
  "debug": false
}

Étape 3. Couche C : Langfuse (observabilité)

Langfuse se lance via Docker Compose (image langfuse/langfuse:2) sur le port 3001. L’intégration Claude Code se fait via le hook Stop. Dashboard : http://localhost:3001.

Les contreparties

Latence : Hindsight ajoute 1-3 secondes par prompt. Sur 50 échanges, ~2 minutes. Perceptible, pas bloquant.

Faux positifs : BRAKE peut bloquer des actions légitimes (refactoring sans DB query). Mitigation : mode log-only la première semaine (exit 0 + log), review, puis activation progressive.

Maintenance : 3 systèmes = 3 points de défaillance. Dégradation gracieuse partout : trap 'exit 0' ERR dans gate.sh, Langfuse passif.

L’état actuel (28 mars 2026)

CoucheStatusDétail
A : BRAKE HardOpérationnel5 règles exit 2, dégrade gracieusement, testé
B : HindsightOpérationnel232 faits extraits, 51 observations, recall fonctionne
C : LangfuseÀ déployerPrévu ce week-end

La question : est-ce que ça change réellement le comportement de l’IA au quotidien ? Métriques à suivre : blocages BRAKE, pertinence recall, taux de conformité, temps gagné vs perdu.

Rendez-vous dans un mois

Ce système est en production sur tous mes projets Claude Code. Le 28 avril 2026, article de suivi avec les données réelles : combien de blocages, combien de faux positifs, combien de recalls pertinents. Et le verdict honnête.

Parce que c’est facile de construire un système. C’est autre chose de vivre avec.

David Perrot, Ingénieur en Informatique, Testeur de limites, constructeur de garde-fous.

Liens
Hindsight (vectorize-io) : Système de mémoire agent
Langfuse : Observabilité pour LLM
Claude Code · Hooks Claude Code
#ClaudeCode#Guardrails #Hindsight#Langfuse #AgentsIA#legeektech

Tu ne codes plus. Tu recrutes.

Après un an à empiler des automatisations, n8n, scripts Python, Notion, Obsidian, j’ai tout viré. Cette semaine, j’ai basculé sur une autre approche. Tu traites ton LLM comme une équipe, pas comme un outil.

Intro

Après un an à empiler des automatisations, n8n, scripts Python, Notion, Obsidian, j’ai tout viré. Le problème : j’automatisais des tâches, pas des compétences. Cette semaine, j’ai basculé sur une autre approche. Tu traites ton LLM comme une équipe, pas comme un outil. Voici comment monter la tienne en 30 minutes.

Prérequis

  • Claude Code (plan Pro ou Max)
  • Un terminal
  • Un dossier vide

Étape 1. Créer le workspace

Structure de départ. Trois dossiers, c’est tout.

mkdir ai-team
cd ai-team
mkdir -p "Owner inbox" "Team inbox" "Team" ".claude/agents"
touch "Owner inbox/.gitkeep" "Team inbox/.gitkeep"
Owner inbox/Livrables finis. Seul l’orchestrateur écrit ici.
Team inbox/Drop zone. Tu déposes des fichiers, l’équipe les traite.
Team/Profils lisibles de chaque membre + roster.
.claude/agents/Définitions techniques des agents.

Cette structure impose un flux. Tu ne parles jamais aux agents directement. Tout passe par l’orchestrateur.

Étape 2. Écrire le CLAUDE.md

Le CLAUDE.md, c’est la constitution. Les règles que tous les agents lisent au démarrage.

touch CLAUDE.md
# Max — AI Team Orchestrator

## Identite
- Nom : Max
- Role : Orchestrateur — chef d'equipe IA
- Regle absolue : Max ne fait JAMAIS le travail. Il delegue, supervise, controle.

## Architecture du workspace
| Dossier | Role |
|---------|------|
| .claude/agents/ | Definitions agents |
| Team/ | Profils lisibles + roster.md |
| Owner inbox/ | Livrables finis — seul Max ecrit ici |
| Team inbox/ | Drop zone — seul Max lit et archive |

## Orchestration
TOUT passe par Max. Tu ne t'adresses jamais aux membres directement.
Flow : Max lit le roster → identifie l'expertise → delegue → controle → livre dans Owner inbox/ → reporte

Étape 3. Créer les 3 agents permanents

max.md : L’orchestrateur

---
name: max
description: Orchestrateur — delegue les taches, ne les execute jamais
model: opus
tools: [Read, Glob, Grep, Agent, Bash]
maxTurns: 50
---

bob.md : Le chercheur

---
name: bob
description: Senior Researcher — recherche, analyse, briefs de recrutement
model: opus
tools: [Read, Grep, Glob, WebFetch, WebSearch]
maxTurns: 30
---

helen.md : La DRH

---
name: helen
description: HR & Team Builder — cree les agents a partir des briefs de Bob
model: sonnet
tools: [Read, Write, Glob, Grep]
maxTurns: 20
---
# Team Roster
| Nom | Role | Modele | Statut |
|-----|------|--------|--------|
| Max | Orchestrateur | opus | Active |
| Bob | Senior Researcher | opus | Active |
| Helen | HR & Team Builder | sonnet | Active |

Étape 4. Le hiring pipeline

Quand aucun membre existant ne couvre une expertise, Max déclenche le recrutement.

Max identifie un manque → Bob recherche le métier correspondant → Helen crée l’agent (.claude/agents/ + Team/ + roster.md) → Max délègue → Tâche terminée → agent supprimé.

Concrètement : tu demandes « Max, j’ai besoin d’un audit SEO. » Max voit que personne ne fait ça. Demande à Bob de briefer. Bob retourne un brief. Helen crée l’agent. Max délègue. Audit livré. Agent supprimé.

Étape 5. La DB SQLite locale

Zéro SaaS. Une base locale pour stocker journal, contacts, projets, connaissances.

CREATE TABLE journal (id INTEGER PRIMARY KEY, date TEXT, content TEXT, tags TEXT, mood TEXT);
CREATE TABLE contacts (id INTEGER PRIMARY KEY, name TEXT, company TEXT, role TEXT, email TEXT, notes TEXT);
CREATE TABLE projects (id INTEGER PRIMARY KEY, name TEXT, status TEXT, description TEXT, deadline TEXT);
CREATE TABLE knowledge (id INTEGER PRIMARY KEY, title TEXT, content TEXT, category TEXT, tags TEXT, source TEXT);

Étape 6. Premier test

Lance Claude Code dans le dossier. Demande : « Max, crée-moi un rapport sur les 3 frameworks JavaScript les plus utilisés en 2026. »

Ce qui va se passer : Max lit le roster → voit que Bob peut rechercher → délègue → Bob retourne ses findings → Max contrôle → dépose dans Owner inbox/ → recap.

Conclusion

Le principe : tu ne codes plus. Tu recrutes.

Spoiler : ça marche pour tous les projets. Posts LinkedIn, audits techniques, documentation, scraping, même flux.

Cette approche vient d’une vidéo de Tom Solid. Je n’ai rien inventé, j’ai juste appliqué et documenté.
Sources
Inspiration : Tom Solid (YouTube) · Implémentation : David Perrot · Code : github.com/dpt73/ai-team-workspace
#ClaudeCode#AgentsIA #Orchestration#Automatisation #legeektech

Claude Code

Barre de contexte segmentée pour Claude Code

Remplace le pourcentage brut de la statusline par une barre visuelle segmentée en couleurs. Tu vois en un coup d’œil ce qui consomme ton contexte : conversation, cache MCP, contexte chargé, ou tokens de sortie. Le pourcentage global passe du vert au jaune à 50 %, puis au rouge à 80 %.

Langage : Bash Prérequis : jq, bc Testé sur : macOS / Linux
statusline-command.sh
#!/bin/bash
# Claude Code status line — barre de contexte segmentée
# Par David Perrot — legeek.tech
input=$(cat)

used_pct=$(echo "$input" | jq -r '.context_window.used_percentage // empty')
ctx_size=$(echo "$input" | jq -r '.context_window.context_window_size // empty')
input_tokens=$(echo "$input" | jq -r '.context_window.current_usage.input_tokens // empty')
cache_read=$(echo "$input" | jq -r '.context_window.current_usage.cache_read_input_tokens // empty')
cache_write=$(echo "$input" | jq -r '.context_window.current_usage.cache_creation_input_tokens // empty')
output_tokens=$(echo "$input" | jq -r '.context_window.current_usage.output_tokens // empty')
model=$(echo "$input" | jq -r '.model.display_name // empty')
cwd=$(echo "$input" | jq -r '.workspace.current_dir // empty')

RST="\033[0m"; BLD="\033[1m"; DIM="\033[2m"
FG_GRN="\033[32m"; FG_YEL="\033[33m"; FG_RED="\033[31m"; FG_CYN="\033[36m"
BG_CYN="\033[46m"; BG_MAG="\033[45m"; BG_GRN="\033[42m"; BG_YEL="\033[43m"
BG_DIM="\033[100m"; DARK="\033[30m"; WHT="\033[97m"

pct_of() {
  local val="$1"
  [ -z "$val" ] || [ "$val" = "null" ] || [ "$val" = "0" ] && echo "0" && return
  [ -z "$ctx_size" ] || [ "$ctx_size" = "0" ] && echo "0" && return
  echo "scale=0; $val * 100 / $ctx_size" | bc
}

# Render segment: n chars wide, bg color, short label, full label
bar_seg() {
  local n="$1" bg="$2" short="$3" full="$4"
  [ "$n" -le 0 ] && return

  # Choose label that fits
  local lbl=""
  if   [ "$n" -ge "${#full}"  ]; then lbl="$full"
  elif [ "$n" -ge "${#short}" ]; then lbl="$short"
  elif [ "$n" -ge 2 ]          ; then lbl="${short:0:$n}"
  fi

  local ll=${#lbl}
  local pad=$(( n - ll ))
  local pl=$(( pad / 2 ))
  local pr=$(( pad - pl ))

  printf "${bg}${DARK}"
  [ "$pl" -gt 0 ] && printf '%*s' "$pl" ''
  printf '%s' "$lbl"
  [ "$pr" -gt 0 ] && printf '%*s' "$pr" ''
  printf "${RST}"
}

if [ -z "$used_pct" ]; then
  printf "${FG_CYN}%s${RST}  %s" "$model" "$(basename "$cwd")"
else
  used_int=$(printf "%.0f" "$used_pct")

  pct_conv=$(pct_of "$input_tokens")
  pct_mcp=$(pct_of "$cache_write")
  pct_ctxt=$(pct_of "$cache_read")
  pct_out=$(pct_of "$output_tokens")

  # Global color
  if   [ "$used_int" -ge 80 ] 2>/dev/null; then gc="$FG_RED"
  elif [ "$used_int" -ge 50 ] 2>/dev/null; then gc="$FG_YEL"
  else gc="$FG_GRN"; fi

  printf "${BLD}${gc}%3d%%${RST} " "$used_int"

  BAR_W=48

  # Used portion in chars
  used_w=$(( used_int * BAR_W / 100 ))
  [ "$used_w" -lt 1 ] && used_w=0

  # Raw segment widths proportional within the used portion
  if [ "$used_int" -gt 0 ]; then
    w_conv=$(( pct_conv * used_w / used_int ))
    w_mcp=$(( pct_mcp  * used_w / used_int ))
    w_ctxt=$(( pct_ctxt * used_w / used_int ))
    w_out=$(( pct_out  * used_w / used_int ))
  else
    w_conv=0; w_mcp=0; w_ctxt=0; w_out=0
  fi

  # Enforce minimum 2 chars for any non-zero segment
  MIN=2
  bump=0
  for v in pct_conv pct_mcp pct_ctxt pct_out; do
    eval "pv=\$$v"
    eval "wv=w_$(echo $v | sed 's/pct_//')"
    eval "wval=\$$wv"
    if [ "$pv" -gt 0 ] && [ "$wval" -lt "$MIN" ]; then
      eval "$wv=$MIN"
      bump=$(( bump + MIN - wval ))
    fi
  done

  # Steal bump from the largest segment
  largest="w_conv"
  lval=$w_conv
  for ww in w_mcp w_ctxt w_out; do
    eval "tv=\$$ww"
    if [ "$tv" -gt "$lval" ]; then lval=$tv; largest=$ww; fi
  done
  eval "$largest=$(( $lval - bump ))"
  eval "[ \$$largest -lt 0 ] && $largest=0"

  # Recompute totals
  filled=$(( w_conv + w_mcp + w_ctxt + w_out ))
  diff=$(( used_w - filled ))
  w_conv=$(( w_conv + diff ))
  [ "$w_conv" -lt 0 ] && w_conv=0

  unused_w=$(( BAR_W - used_w ))
  [ "$unused_w" -lt 0 ] && unused_w=0

  # Render: CONV | MCP | CTXT | OUT | unused
  bar_seg "$w_conv"  "$BG_CYN" "CONV"  "CONV ${pct_conv}%"
  bar_seg "$w_mcp"   "$BG_MAG" "MCP"   "MCP ${pct_mcp}%"
  bar_seg "$w_ctxt"  "$BG_GRN" "CTXT"  "CTXT ${pct_ctxt}%"
  bar_seg "$w_out"   "$BG_YEL" "OUT"   "OUT ${pct_out}%"

  if [ "$unused_w" -gt 0 ]; then
    printf "${BG_DIM}${DARK}%*s${RST}" "$unused_w" ''
  fi
fi

Installation

  1. Ouvre ton terminal. Le dossier de config de Claude Code est caché dans ton home : ~/.claude/. Si tu ne le vois pas dans ton explorateur de fichiers, c’est normal, les dossiers qui commencent par un point sont masqués par défaut.
  2. Crée le fichier du script :
    nano ~/.claude/statusline-command.sh
    Colle le script complet copié ci-dessus, puis sauvegarde avec Ctrl+O, Enter, Ctrl+X.
  3. Rends le fichier exécutable, sans ça, Claude Code ne pourra pas le lancer :
    chmod +x ~/.claude/statusline-command.sh
  4. Ouvre (ou crée) le fichier de settings de Claude Code :
    nano ~/.claude/settings.json
    Ajoute cette ligne dans le JSON :
    "statusline": { "command": "bash ~/.claude/statusline-command.sh" }
    Si le fichier existe déjà avec d’autres réglages, ajoute cette clé à côté des autres (sans oublier la virgule de séparation).
  5. Ferme et relance Claude Code. La barre segmentée apparaît en bas de ton terminal.
Prérequis : jq doit être installé (traitement JSON en ligne de commande).
Sur Mac : brew install jq · Sur Ubuntu/Debian : sudo apt install jq

Terminal / macOS

Fastfetch : Infos système et logo Apple au lancement du terminal

Affiche les infos système (OS, CPU, RAM, GPU, batterie, uptime) avec le logo Apple en ASCII à chaque ouverture de terminal. Remplace Neofetch (archivé, plus maintenu). Écrit en C, quasi instantané, là où Neofetch pouvait mettre 2 secondes.

Outil : fastfetch (Homebrew) Config : JSONC Testé sur : macOS / Linux
config.jsonc : ~/.config/fastfetch/
{
  "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
  "logo": {
    "type": "small"
  },
  "display": {
    "separator": " → "
  },
  "modules": [
    "title",
    "separator",
    "os",
    "kernel",
    "shell",
    "terminal",
    "cpu",
    "gpu",
    "memory",
    "disk",
    "battery",
    "uptime",
    "break",
    "colors"
  ]
}

Installation

  1. Ouvre le fichier de config :
    nano ~/.config/fastfetch/config.jsonc
    Remplace le contenu par la config ci-dessus, ou ajuste les modules selon tes préférences. Les modules disponibles : os, kernel, shell, terminal, cpu, gpu, memory, disk, battery, uptime, colors, locale, wifi, packages
  2. Active le lancement automatique à chaque ouverture de terminal :
    echo '[[ $- == *i* ]] && fastfetch' >> ~/.zshrc
    La condition [[ $- == *i* ]] empêche le lancement dans les scripts non-interactifs (cron, CI, etc.).
  3. Ouvre un nouveau terminal. Fastfetch s’affiche automatiquement avec tes infos système.
Options utiles :
Logo petit : "type": "small" · Logo personnalisé : "source": "/chemin/vers/ascii.txt"
Séparateur custom : "separator": " → " ou " : " ou " ── "
Désactiver un module : supprime-le simplement de la liste "modules".

OpenClaw / Docker

Remplacer Brave Search par SearXNG dans OpenClaw : zéro frais

Brave Search API coûte 4 dollars par mois. SearXNG auto-hébergé fait la même chose gratuitement. On remplace le fournisseur de recherche web d’OpenClaw en 10 minutes : un fichier de config SearXNG, un service Docker Compose, et trois lignes dans openclaw.json.

Outils : Docker, SearXNG Prérequis : VPS avec OpenClaw Temps : 10 min
~/searxng/settings.yml
use_default_settings: true

general:
  instance_name: "OpenClaw SearXNG"
  enable_metrics: false

search:
  safe_search: 0
  default_lang: "fr"
  formats:
    - html
    - json

server:
  secret_key: "changez-moi-par-une-vraie-cle"
  bind_address: "0.0.0.0"
  port: 8080
  limiter: false
  public_instance: false

engines:
  - name: google
    engine: google
    shortcut: g
    disabled: false
  - name: duckduckgo
    engine: duckduckgo
    shortcut: ddg
    disabled: false
  - name: bing
    engine: bing
    shortcut: b
    disabled: false
  - name: wikipedia
    engine: wikipedia
    shortcut: wp
    disabled: false
docker-compose.yml : service à ajouter
  searxng:
    image: searxng/searxng:latest
    volumes:
      - ~/searxng/settings.yml:/etc/searxng/settings.yml:ro
      - ~/searxng/limiter.toml:/etc/searxng/limiter.toml:ro
    restart: unless-stopped
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETGID
      - SETUID
~/.openclaw/openclaw.json : section tools
{
  "tools": {
    "web": {
      "search": {
        "enabled": true,
        "provider": "searxng",
        "searxng": {
          "baseUrl": "http://searxng:8080"
        }
      }
    }
  }
}

Installation

  1. Crée le dossier de config SearXNG :
    mkdir -p ~/searxng
  2. Crée le fichier ~/searxng/settings.yml avec la config ci-dessus. Le format JSON (formats: [html, json]) est indispensable pour qu’OpenClaw puisse parser les résultats.
  3. Crée un fichier vide requis par SearXNG :
    touch ~/searxng/limiter.toml
  4. Ajoute le service searxng dans ton docker-compose.yml OpenClaw. Pas besoin d’exposer de port, les deux services communiquent via le réseau Docker interne.
  5. Ouvre ~/.openclaw/openclaw.json et remplace (ou ajoute) la section tools avec la config ci-dessus. Les trois lignes clés : "provider": "searxng", "baseUrl": "http://searxng:8080", "enabled": true.
  6. Redémarre les services :
    docker compose up -d
  7. Vérifie que SearXNG tourne :
    docker ps | grep searxng
    Puis pose une question web à OpenClaw pour tester.
Le calcul : Brave Search API = 48 CHF/an. Tavily = 60 CHF/an. SearXNG = 0 CHF (~50 Mo de RAM).
Source : docs.searxng.org

Sécurité

Glassworm : Protection contre l’attaque qui a compromis 400+ dépôts

En mars 2026, Glassworm a injecté du code malveillant dans des paquets npm, pip et extensions VSCode via des credentials GitHub volés. Les scripts ci-dessous permettent d’auditer ses dépendances, de vérifier ses commits et d’activer la signature GPG.

🏷️ Langage : Bash / CLI 📦 Prérequis : npm, pip, git, gpg ✓ Testé sur : macOS / Linux
Étape 1. Audit des dépendances
#!/bin/bash
# Audit rapide de tous tes projets Node.js et Python
# Usage: chmod +x audit-deps.sh && ./audit-deps.sh

echo "=== Audit des dependances ==="
echo ""

# Node.js
if command -v npm &>/dev/null; then
  echo "[npm] Scan en cours..."
  npm audit 2>/dev/null || echo "[npm] Aucun projet Node.js ici"
  echo ""
fi

# Python
if command -v pip &>/dev/null; then
  if ! command -v pip-audit &>/dev/null; then
    echo "[pip] Installation de pip-audit..."
    pip install pip-audit -q
  fi
  echo "[pip] Scan en cours..."
  pip-audit 2>/dev/null || echo "[pip] Aucun environnement Python actif"
  echo ""
fi

echo "=== Audit termine ==="
Étape 2. Vérifier les commits suspects
#!/bin/bash
# Verifie les commits suspects depuis le 8 mars 2026

echo "=== Commits depuis le 8 mars ==="
git log --since="2026-03-08" --stat --oneline

echo ""
echo "=== Diff avec le remote ==="
git diff origin/main..HEAD --stat

echo ""
echo "=== Reflog (detecte les force-push) ==="
git reflog --since="2026-03-08" | head -20
Étape 3. Activer la signature GPG
#!/bin/bash
# Active la signature GPG sur tous tes commits

# Genere une cle GPG (RSA 4096, pas d'expiration)
gpg --full-generate-key

# Recupere l'ID de ta cle
KEY_ID=$(gpg --list-secret-keys --keyid-format=long \
  | grep sec | awk '{print $2}' | cut -d"/" -f2)
echo "Cle GPG: $KEY_ID"

# Configure Git globalement
git config --global user.signingkey $KEY_ID
git config --global commit.gpgsign true

Protection complète en 5 étapes

  1. Audite tes dépendances :
    npm audit et pip audit sur chaque projet actif
  2. Vérifie les commits depuis le 8 mars :
    git log --since="2026-03-08" --stat
  3. Pin tes versions dans package.json, remplace ^4.17.0 par 4.17.21 puis npm ci
  4. Installe un scanner continu :
    npx socket report create ou aikido.dev (gratuit ≤ 10 repos)
  5. Active la signature GPG :
    git config --global commit.gpgsign true

NemoClaw / NVIDIA : NOUVEAU

NemoClaw (NVIDIA) : installation pas à pas sur VPS sans GPU

Testé le 18 mars 2026. 4 heures d’installation, 10 problèmes rencontrés et résolus. Du faux paquet npm au sandbox fonctionnel avec Nemotron 3 Super 120B. Chaque commande ci-dessous a été exécutée sur un VPS Hostinger (Ubuntu 24.04, 4 vCPU, 16 GB RAM, Docker 29.3, Node 22, zéro GPU).

Outils : OpenShell, NemoClaw, Docker Prérequis : VPS Ubuntu 22.04+, Docker, Node 20+ Temps : ~4h (avec les pièges documentés, comptez 1h)

Étape 1. Vérifier les prérequis

  1. Vérifiez que tout est en place avant de commencer. NemoClaw ne donne aucun message d’erreur clair si un prérequis manque.
Vérification des prérequis
uname -a            # Ubuntu 22.04 ou supérieur
docker --version    # Docker 20+ installé et running
node --version      # Node.js 20+
free -h             # 16 GB recommandé (8 GB minimum + swap)
df -h /             # 40 GB libres (image sandbox = 2 GB)

Étape 2. Installer OpenShell

  1. OpenShell est le runtime de sécurité de NVIDIA (binaire Rust statique, 13 MB). C’est lui qui crée le sandbox. Sans lui, NemoClaw refuse de démarrer.
Installation OpenShell
ARCH=$(uname -m)
curl -sL -o /tmp/openshell.tar.gz \
  "https://github.com/NVIDIA/OpenShell/releases/latest/download/openshell-${ARCH}-unknown-linux-musl.tar.gz"

cd /tmp && tar xzf openshell.tar.gz

# Vérifier que c'est un vrai binaire
file openshell
# ELF 64-bit LSB pie executable, x86-64, static-pie linked

install -m 755 openshell /usr/local/bin/openshell
openshell --version
# openshell 0.0.10

rm /tmp/openshell /tmp/openshell.tar.gz

Étape 3. Installer NemoClaw

PIÈGE : Il existe un faux paquet npm nemoclaw (typosquatting). Ne pas faire npm install -g nemoclaw. Cloner depuis GitHub directement.
Installation NemoClaw depuis GitHub
cd /opt
git clone https://github.com/NVIDIA/NemoClaw.git
cd NemoClaw

# Vérifier que c'est le bon repo
head -6 package.json
# "description": "NemoClaw — run OpenClaw inside OpenShell with NVIDIA inference"
# "license": "Apache-2.0"
# "bin": { "nemoclaw": "./bin/nemoclaw.js" }

npm install -g .
nemoclaw --help   # Doit afficher le menu CLI

Étape 4. Clé API NVIDIA (gratuit)

  1. Aller sur build.nvidia.com
  2. Créer un compte (pas de carte bancaire)
  3. Profil → API Keys → Generate API Key
  4. Copier la clé (format nvapi-...)
Sauvegarder la clé (permissions 600)
mkdir -p ~/.nemoclaw && chmod 700 ~/.nemoclaw
echo '{"nvidia_api_key":"nvapi-VOTRE_CLE"}' > ~/.nemoclaw/credentials.json
chmod 600 ~/.nemoclaw/credentials.json

Étape 5. Patcher le port 8080 AVANT le onboard

ERREUR RENCONTRÉE : failed to bind host port 0.0.0.0:8080/tcp: address already in use. Le gateway utilise le port 8080 par défaut. Si un autre service l’occupe, le onboard plante sans alternative. Il faut patcher le code source.
Patch du port 8080 → 8180
# Vérifier si le port 8080 est occupé
lsof -i :8080

# Si oui, patcher le onboard
sed -i 's/const gwArgs = \["--name", "nemoclaw"\];/const gwArgs = ["--name", "nemoclaw", "--port", "8180"];/' \
  /opt/NemoClaw/bin/lib/onboard.js

# Vérifier le patch
grep 'gwArgs' /opt/NemoClaw/bin/lib/onboard.js
# const gwArgs = ["--name", "nemoclaw", "--port", "8180"];

Étape 6. Libérer le port 18789

ERREUR RENCONTRÉE : Port 18789 is already in use. Si OpenClaw tourne déjà sur ce port, il faut le stopper temporairement.
Libérer le port 18789
lsof -i :18789

# Si occupé par OpenClaw
docker stop openclaw-openclaw-gateway-1 openclaw-searxng-1

# Pour rollback plus tard :
# docker start openclaw-openclaw-gateway-1 openclaw-searxng-1

Étape 7. Lancer le wizard onboard

  1. Le wizard est interactif. Il demande : un nom de sandbox, le choix du provider (prendre NVIDIA Cloud API), et les policies à appliquer (accepter les suggestions).
  2. L’image Docker fait ~2 GB. Comptez 5-10 minutes de téléchargement.
  3. Si erreur tar entry path too long : vous avez un dossier openclaw local. Supprimez le sandbox échoué (openshell sandbox delete NOM) et relancez.
Lancement du onboard
export NVIDIA_API_KEY='nvapi-VOTRE_CLE'
nemoclaw onboard

# Le wizard déroule 7 étapes :
# [1/7] Preflight   — Docker OK, OpenShell OK, No GPU → cloud
# [2/7] Gateway     — démarre sur port 8180 (patché)
# [3/7] Sandbox     — télécharge ~2 GB, crée le sandbox
# [4/7] Inference   — Nemotron 3 Super 120B via NVIDIA Cloud
# [5/7] Provider    — nvidia-nim créé
# [6/7] OpenClaw    — lancé dans le sandbox
# [7/7] Policies    — pypi, npm appliquées

Étape 8. Vérifier l’installation

Vérification complète
nemoclaw status                    # Liste le sandbox
nemoclaw nemoclaw-test status      # Phase: Ready
openshell status                   # Status: Connected
openshell sandbox list             # nemoclaw-test Ready

# Test de connexion au sandbox
printf 'whoami && openclaw --version\nexit\n' | \
  timeout 15 openshell sandbox connect nemoclaw-test
# sandbox           ← PAS root (isolation OK)
# OpenClaw 2026.3.11

Étape 9. Résoudre le problème d’authentification

ERREUR RENCONTRÉE : No API key found for provider "anthropic". L’agent vérifie la présence d’une clé Anthropic AVANT d’envoyer la requête, même si OpenShell reroute vers Nemotron. Solution : fausse clé Anthropic + vraies credentials NVIDIA.
Premier test avec l’agent (env vars obligatoires)
printf 'export ANTHROPIC_API_KEY=dummy-rerouted-by-nemoclaw
export OPENAI_API_KEY=nvapi-VOTRE_CLE
export OPENAI_BASE_URL=https://integrate.api.nvidia.com/v1
openclaw agent --session-id test -m "Bonjour, qui es-tu ?" --json 2>&1
exit
' | timeout 90 nemoclaw nemoclaw-test connect

# Résultat attendu :
# "status": "ok"
# "provider": "nvidia"
# "model": "nemotron-3-super-120b-a12b"
# Temps de réponse : ~9 secondes

Étape 10. Recherche web avec Gemini (gratuit)

  1. OpenClaw 2026.3.11 n’accepte que : brave, perplexity, grok, gemini. Brave a retiré son tier gratuit (4$/mois). Gemini est gratuit.
  2. Obtenir une clé sur aistudio.google.com/apikey
  3. BUG CONNU : openshell sandbox upload crée un dossier au lieu d’un fichier. Utiliser le heredoc ci-dessous.
Injecter la config Gemini dans le sandbox
# Supprimer l'ancienne config
printf 'rm -f /sandbox/.openclaw/openclaw.json\nexit\n' | \
  timeout 10 openshell sandbox connect nemoclaw-test

# Écrire la config avec Gemini (ADAPTER votre clé)
printf 'cat > /sandbox/.openclaw/openclaw.json << "ENDCFG"
{
  "tools": {
    "web": {
      "search": {
        "enabled": true,
        "provider": "gemini",
        "gemini": {
          "apiKey": "AIzaSy-VOTRE-CLE-GEMINI"
        }
      }
    }
  }
}
ENDCFG
echo DONE
exit
' | timeout 15 openshell sandbox connect nemoclaw-test
Créer et appliquer la policy réseau Gemini
cat > /opt/NemoClaw/nemoclaw-blueprint/policies/presets/gemini-search.yaml << 'YAML'
preset:
  name: gemini-search
  description: "Google Gemini API access for web search"

network_policies:
  gemini_api:
    name: gemini_api
    endpoints:
      - host: generativelanguage.googleapis.com
        port: 443
        protocol: rest
        enforcement: enforce
        rules:
          - allow: { method: GET, path: "/**" }
          - allow: { method: POST, path: "/**" }
      - host: www.googleapis.com
        port: 443
        protocol: rest
        enforcement: enforce
        rules:
          - allow: { method: GET, path: "/**" }
          - allow: { method: POST, path: "/**" }
    binaries:
      - path: /usr/local/bin/openclaw
      - path: /usr/bin/node
YAML

cd /opt/NemoClaw
node -e 'require("./bin/lib/policies").applyPreset("nemoclaw-test", "gemini-search")'
# Applied preset: gemini-search

Étape 11. Bridge Telegram

  1. Problème 1 : le bridge cherche un sandbox nommé nemoclaw par défaut. Passer SANDBOX_NAME au lancement.
  2. Problème 2 : le bridge ne passe pas les env vars d’auth à l’agent. L’agent reçoit les messages mais ne répond jamais. Il faut patcher la ligne 95.
Patch du bridge Telegram (ligne 95)
# Dans /opt/NemoClaw/scripts/telegram-bridge.js
# Ligne 95, REMPLACER :
#   export NVIDIA_API_KEY='${API_KEY}' && nemoclaw-start...
# PAR :
#   export NVIDIA_API_KEY='${API_KEY}' ANTHROPIC_API_KEY=dummy OPENAI_API_KEY='${API_KEY}' OPENAI_BASE_URL=https://integrate.api.nvidia.com/v1 && nemoclaw-start...

# En une commande sed :
sed -i "s|export NVIDIA_API_KEY='\${API_KEY}' \&\& nemoclaw-start|export NVIDIA_API_KEY='\${API_KEY}' ANTHROPIC_API_KEY=dummy OPENAI_API_KEY='\${API_KEY}' OPENAI_BASE_URL=https://integrate.api.nvidia.com/v1 \&\& nemoclaw-start|" \
  /opt/NemoClaw/scripts/telegram-bridge.js
Script de démarrage du bridge
cat > /opt/NemoClaw/start-bridge.sh << 'SH'
#!/bin/bash
export NVIDIA_API_KEY='nvapi-VOTRE_CLE'
export TELEGRAM_BOT_TOKEN='VOTRE_TOKEN_BOTFATHER'
export SANDBOX_NAME='nemoclaw-test'
export ALLOWED_CHAT_IDS='VOTRE_CHAT_ID_TELEGRAM'
pkill -f telegram-bridge 2>/dev/null
sleep 1
nohup node /opt/NemoClaw/scripts/telegram-bridge.js > /tmp/nemoclaw-telegram.log 2>&1 &
echo "Bridge demarre PID=$!"
sleep 3
tail -15 /tmp/nemoclaw-telegram.log
SH
chmod +x /opt/NemoClaw/start-bridge.sh

# Lancer le bridge
bash /opt/NemoClaw/start-bridge.sh

# Surveiller les logs
tail -f /tmp/nemoclaw-telegram.log

Récap des 10 pièges

  1. Dockerfile local → relancer onboard (image ghcr.io)
  2. Credentials masquées → normal (masquage sécurité)
  3. Auth Anthropic → ANTHROPIC_API_KEY=dummy
  4. Nom sandbox bridge → SANDBOX_NAME=votre-nom
  5. Bridge muet → patch ligne 95
  6. SearxNG retiré → Gemini (gratuit) + policy
  7. Upload buggé → heredoc via sandbox connect
Commandes de rollback :
nemoclaw nemoclaw-test destroy : supprime le sandbox
openshell gateway destroy -g nemoclaw : supprime le gateway
docker start openclaw-openclaw-gateway-1 : restaure OpenClaw

Testé et validé le 18 mars 2026 sur VPS Hostinger
4 vCPU AMD EPYC · 16 GB RAM · Ubuntu 24.04 · Docker 29.3 · Node.js 22
David Perrot · legeek.tech

Lire l’analyse complète sous le capot →