--- type: howto titre: "🧰 REGISTRE DES SOLUTIONS IMPORTANTES — OLYMPUS" dossier: 03_HOWTO etage: long source: true # SOURCE (autorite) - les projections (Chroma/graphe) en derivent maj: 2026-05-20 hash: bec4bf7f --- ï»ż--- type: REGISTRE_SOLUTIONS project: OLYMPUS (transverse) status: active created: 2026-04-28 (mission BUILD-002 nocturne) diĂĄtaxis: how-to audience: [tous_les_chats_OLYMPUS, futurs_connecteurs_MCP] auto_indexed_by_codex: true mis_a_jour_par: chaque chat qui dĂ©couvre une solution gĂ©nĂ©rale rĂ©utilisable --- # 🧰 REGISTRE DES SOLUTIONS IMPORTANTES — OLYMPUS > **But** : capitaliser les **dĂ©couvertes techniques importantes** trouvĂ©es par chaque chat OLYMPUS, pour qu'**aucun autre chat ne refasse 2× le mĂȘme problĂšme**. > **Pattern industrie** : Postmortem Knowledge Base · Stack Overflow interne · Architecture Decision Record (ADR lĂ©ger). > **Auto-indexĂ© par CODEX** : ce fichier remonte dans CODEX.html Ă  chaque rĂ©gĂ©nĂ©ration (toutes les 30 min). --- ## 📑 Index par catĂ©gorie - [đŸ€– CLI / Subprocess / Sandboxing](#cli) · S001 - [💬 Chat-Ă -chat / Communication entre Claude](#chat-claude) · S008 - [🌐 WebSocket / FastAPI / NEXUS](#websocket) · S002 - [đŸ–Œïž Capture Ă©cran / OmniParser / Vision](#vision) · S003 - [đŸȘŸ Always-on-top / Window management / FenĂȘtres natives](#window) · S004 S009 - [📩 Imports / Path Windows](#path) · S005 - [đŸ›Ąïž Mona Lisa / Snapshots / Backups](#mona-lisa) · S006 S007 - [🌐 Claude embedded per-app / Vision "Claude partout"](#claude-partout) · S010 --- ## đŸ€– CLI / Subprocess / Sandboxing ### S001 — Claude CLI (`claude.exe`) inaccessible depuis Python (sandboxing Windows AppData) > ✅ **RÉSOLU 2026-05-01** — option (2) appliquĂ©e : `claude.exe` copiĂ© vers `C:\OLYMPUS\AGORA\bin\claude.exe` (243 MB). Python peut l'exĂ©cuter sans souci. `_find_claude_exe()` mis Ă  jour pour prĂ©fĂ©rer ce path. Endpoint `/api/canvas/chat` testĂ© : **200 OK · 5.68s · vraie rĂ©ponse Claude · accents+emojis UTF-8 propres**. Garder cette section pour mĂ©moire historique du diagnostic. **DĂ©couvert par** : BUILD-002 GRAPHISME-001 (Claude Code, 2026-04-28 nuit) **SymptĂŽme** : - `claude.exe` localisĂ© via `find` Bash Ă  `C:\Users\vivie\AppData\Roaming\Claude\claude-code\2.1.119\claude.exe` (254 MB) - `os.path.exists()` Python renvoie `False` sur ce path - `subprocess.run([...])` Ă©choue : `FileNotFoundError [WinError 2]` - `cmd /c "...claude.exe" --version` → "chemin d'accĂšs introuvable" - Pourtant `dir` cmd voit bien le dossier (vide en apparence) - Et Bash msys peut **lister + exĂ©cuter** le binaire normalement **Cause probable** : - Dossier `AppData\Roaming\Claude\` est dans une zone de **redirection / virtualisation** Windows (style App-V ou OneDrive Backup cloud-only) - Python 3.14 standalone n'a pas les permissions ou ne suit pas le redirect - Bash msys utilise un autre layer de filesystem qui contourne **Solutions de contournement (ordre de prĂ©fĂ©rence)** : 1. **ClĂ© API Anthropic** + appel HTTP direct depuis NEXUS : ```python import anthropic client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"]) resp = client.messages.create( model="claude-sonnet-4-5", max_tokens=1024, messages=[{"role": "user", "content": "..."}], ) ``` Avantages : pay-as-you-go, pas d'abonnement, latence API directe (~3-5s) InconvĂ©nients : besoin d'une clĂ© (gratuit Ă  crĂ©er sur console.anthropic.com) 2. **Copier `claude.exe` vers un path accessible** : ```bash cp "C:/Users/vivie/AppData/Roaming/Claude/claude-code/2.1.119/claude.exe" "C:/OLYMPUS/AGORA/bin/claude.exe" ``` Avantages : utilise le binaire local existant InconvĂ©nients : 254 MB · Ă  refaire Ă  chaque update Claude Code · besoin shell qui peut copier (Bash OK) 3. **Ollama local** : - Lancer Ollama (`ollama serve`) sur port 11434 - HTTP POST Ă  `http://localhost:11434/api/chat` Avantages : 100% offline, gratuit InconvĂ©nients : qualitĂ© moindre que Claude · GPU recommandĂ© · install lourde 4. **Chercher dans `WindowsApps` aliases** : ```bash ls C:/Users/vivie/AppData/Local/Microsoft/WindowsApps/ | grep -i claude ``` Si Claude Code a publiĂ© un AppExecutionAlias, il sera lĂ . **Pattern source** : Diagnostic Bash vs Python sandboxing → tester multiple subprocess methods. **Fichiers concernĂ©s** : - `C:\OLYMPUS\01_SERVEUR\NEXUS\AXIOM\api_canvas.py` → fonction `_find_claude_exe()` retourne None gracefully - Endpoint `/api/canvas/chat` → fallback EN CHANTIER message clair --- ## 💬 Chat-Ă -chat / Communication entre Claude (subprocess) ### S008 — Pattern "1 chat Claude par tuile" via subprocess `claude.exe --print` (stateless) **DĂ©couvert par** : BUILD-002 / GRAPHISME-001 (2026-04-30 nuit Vivien — POC `/api/canvas/chat` validĂ©) **IdĂ©e centrale** : `claude.exe --print ""` est un **moteur de rĂ©ponse stateless universel**. Chaque appel = un Claude frais, sans historique, sans contexte global. Parfait pour intĂ©grer un mini-chat dans **n'importe quel composant UI** sans gĂ©rer de session. **Cas d'usage parfait** : "**1 chat par tuile**" dans le Cockpit. Chaque tuile (MĂ©tĂ©o, Agenda, Code, Notes, Mail
) reçoit son propre input texte. L'utilisateur tape sa demande → POST → `claude.exe --print` → reply. La tuile peut ĂȘtre **modifiĂ©e Ă  la volĂ©e** sans contexte global ni state partagĂ©. **Architecture flow** : ``` [Tuile UI] ─POST {"text":"
"}─→ /api//chat (NEXUS Python) ↓ subprocess.run([claude.exe, "--print", text]) ↓ stdout = rĂ©ponse markdown ↓ [Tuile UI] ←─{ok:true, reply:"
", duration_sec:N}── JSON ``` **Code de rĂ©fĂ©rence (validĂ© en prod)** : `C:\OLYMPUS\01_SERVEUR\NEXUS\AXIOM\api_canvas.py` lignes 308-398 (endpoint `/api/canvas/chat`). **Recette minimale (Ă  copier dans `api_.py`)** : ```python import glob, subprocess, asyncio, os, time from fastapi import APIRouter, Body from typing import Dict, Any router = APIRouter() def _find_claude_exe() -> str | None: """Auto-dĂ©tecte le path le plus rĂ©cent de claude.exe.""" candidates = glob.glob(r"C:/Users/vivie/AppData/Roaming/Claude/claude-code/*/claude.exe") return sorted(candidates)[-1] if candidates else None @router.post("/api//chat", tags=[""]) async def chat(payload: Dict[str, Any] = Body(...)) -> Dict[str, Any]: text = (payload.get("text") or "").strip() if not text: return {"ok": False, "error": "text vide"} claude_exe = _find_claude_exe() if not claude_exe: # Fallback EN CHANTIER (cf. S001 : sandboxing AppData Windows) return { "ok": True, "reply": f"💬 EN CHANTIER : claude.exe inaccessible. Tu m'as dit : « {text} ».", "status": "EN_CHANTIER", } # CRITIQUE : fix UTF-8 Windows cp1252 → UTF-8 (sinon "Ă©" devient "é", "🎯" devient "Ă°ĆžĆœÂŻ") env = os.environ.copy() env['PYTHONIOENCODING'] = 'utf-8' env['PYTHONUTF8'] = '1' env['LANG'] = 'fr_FR.UTF-8' started = time.time() try: # Subprocess en thread pour ne pas bloquer asyncio loop = asyncio.get_event_loop() result = await loop.run_in_executor( None, lambda: subprocess.run( [claude_exe, "--print", text], capture_output=True, text=False, # bytes → on dĂ©code nous-mĂȘme (plus fiable) timeout=90, env=env, ), ) # DĂ©codage robuste multi-encoding def decode_safe(data: bytes) -> str: if not data: return "" for enc in ('utf-8', 'cp65001', 'cp1252', 'latin-1'): try: return data.decode(enc) except UnicodeDecodeError: continue return data.decode('utf-8', errors='replace') stdout = decode_safe(result.stdout) stderr = decode_safe(result.stderr) duration = round(time.time() - started, 2) if result.returncode != 0: return {"ok": False, "error": f"exit {result.returncode}", "stderr": stderr[:500], "duration_sec": duration} return {"ok": True, "reply": stdout.strip(), "duration_sec": duration} except subprocess.TimeoutExpired: return {"ok": False, "error": "timeout 90s"} except Exception as e: return {"ok": False, "error": f"{type(e).__name__}: {e}"} ``` **Personnalisation par tuile (prompt-prefix injectĂ©)** : ```python TUILE_PROMPTS = { "weather": "Tu es mĂ©tĂ©o expert. RĂ©ponds en 3 lignes max. Question: ", "calendar": "Tu es agenda Vivien. RĂ©ponds en bullets courts. Question: ", "code": "Tu es Senior Dev OLYMPUS. Code uniquement, pas d'explication verbeuse. Question: ", "notes": "Tu es preneur de notes. Reformule + tag #thĂšme. Note: ", "mail": "Tu es rĂ©dacteur email FR pro. Style clair. Brief: ", } prefix = TUILE_PROMPTS.get(tuile_id, "") result = subprocess.run([claude_exe, "--print", prefix + text], ...) ``` **Quand utiliser ce pattern** : - ✅ "1 chat par tuile" Cockpit (cas d'usage Vivien validĂ© 30/04/2026) - ✅ TĂąches stateless courtes : "rĂ©sume ce texte", "gĂ©nĂšre un email", "explique ce code" - ✅ Pas besoin d'historique de conversation (chaque message = fresh start) - ✅ Personnalisation par contexte : prĂ©fixe rĂŽle + question utilisateur **Quand NE PAS utiliser** : - ❌ Conversations longues avec mĂ©moire (utiliser API Anthropic + state local) - ❌ Streaming de rĂ©ponse (subprocess `--print` bloque jusqu'Ă  fin) - ❌ Beaucoup de tuiles en parallĂšle (chaque subprocess Claude = 200-500 MB RAM) **Fix UTF-8 critique (bug observĂ© Vivien 01/05/2026)** : - Sans `PYTHONUTF8=1` + `decode_safe()` : `Ă©` devient `é`, `🎯` devient `Ă°ĆžĆœÂŻ` - Cause : Windows console default cp1252, Claude CLI sort UTF-8, Python dĂ©code en cp1252 → cassĂ© - Fix testĂ© en prod sur `/api/canvas/chat` ✅ **PrĂ©-requis (S001)** : - `claude.exe` doit ĂȘtre trouvable. Si `_find_claude_exe()` renvoie `None` → fallback `EN_CHANTIER` (sans crasher l'UI). - Solutions de dĂ©blocage en cas de sandboxing AppData : voir S001 (clĂ© API · copier exe vers AGORA/bin · Ollama local). **Fichiers concernĂ©s** : - `C:\OLYMPUS\01_SERVEUR\NEXUS\AXIOM\api_canvas.py` (ref impl ligne 308-398) - À rĂ©pliquer dans `api_.py` pour chaque tuile Cockpit qui veut son chat **Pattern industrie** : - **Process-as-API** (Unix philosophy 1978) - **Stateless microservices** (Heroku 12-factor 2011) - **Sidecar pattern** (Kubernetes 2015) — chaque tuile = son propre worker --- ### 🎯 Usages connus + futurs (formalisation 01/05/2026 — demande Vivien) **Vivien (01/05 13h00)** : *"j'espĂšre que la mĂ©thode pour activer des chat claude est marquĂ©e bien quelque part dans nexus il faudra se servir de ça plus tard pour la sphĂšre goku et pour que je parle avec Claude en direct projet jarvis , formalise tout ça"* | Module | Statut | Endpoint | Notes | |---|---|---|---| | **Canvas Vivant** | ✅ en prod | `/api/canvas/chat` | RĂ©fĂ©rence implĂ©mentation, validĂ© chat LGS | | **Cockpit V3 — chat-par-tuile** | ✅ livrĂ© 01/05 | `/api/canvas/chat` (rĂ©utilisĂ©) | 4 tuiles GridStack dĂ©mo cliquables | | **SphĂšre Goku** | 📅 Ă  venir | `/api/sphere/chat` (Ă  crĂ©er) | Vivien parlera Ă  Goku via subprocess Claude | | **Jarvis (parler en direct)** | 📅 Ă  venir | `/api/jarvis/chat` ou WS streaming | Conversation continue, peut nĂ©cessiter API directe pour streaming | | **Modules autres** | 📅 possible | `/api//chat` | Chaque module peut avoir son chat dĂ©diĂ© si besoin | ### ⚠ Limites du pattern (Ă  connaĂźtre pour les usages futurs) | Limite | DĂ©tail | Mitigation | |---|---|---| | **Internet requis** | `claude.exe` appelle api.anthropic.com en HTTPS | Fallback Ollama local pour offline | | **Latence 5-15s** | subprocess + appel API Anthropic | UI loader obligatoire ("Claude rĂ©flĂ©chit
") | | **RAM ~300 MB par appel** | Chaque `claude.exe` lance un process | Limiter Ă  2-3 chats parallĂšles (queue/throttle) | | **Stateless** | Aucun contexte prĂ©servĂ© entre appels | OK pour modifications ponctuelles, pas pour conversation longue | | **Pas de streaming** | `--print` bloque jusqu'Ă  la rĂ©ponse complĂšte | Pour streaming → API Anthropic directe (clĂ© requise) | ### đŸ› ïž Pattern fallback offline (Ă  coder pour Jarvis si besoin) ```python async def chat_with_fallback(text: str) -> dict: # 1. Essayer claude.exe (cloud) try: result = await run_claude_subprocess(text, timeout=15) if result["ok"]: return result except Exception: pass # 2. Fallback Ollama local (offline) try: async with aiohttp.ClientSession() as session: async with session.post( "http://localhost:11434/api/chat", json={"model": "llama3.1", "messages": [{"role": "user", "content": text}]} ) as r: data = await r.json() return {"ok": True, "reply": data["message"]["content"], "source": "ollama_local"} except Exception: return {"ok": False, "error": "Aucun LLM disponible (cloud + offline KO)"} ``` ### 🎓 Recette pour intĂ©grer le chat-par-X dans un nouveau module 1. **Frontend** : copier le pattern HTML+CSS+JS de cockpit_v3 (`tile-chat-wrap`, `tile-chat-input`, `tile-chat-reply`) 2. **Backend** : soit rĂ©utiliser `/api/canvas/chat` (chat gĂ©nĂ©rique), soit crĂ©er un endpoint dĂ©diĂ© `/api//chat` avec prĂ©fixe rĂŽle (cf. `TUILE_PROMPTS` dans BRIEF) 3. **Fallback** : si offline critique → ajouter le pattern Ollama ci-dessus 4. **Test E2E** : `curl -X POST .../chat -d '{"text":"hello"}'` doit rĂ©pondre en <30s --- ## 🌐 WebSocket / FastAPI / NEXUS ### S002 — Ajouter un WebSocket Ă  NEXUS sans casser l'existant **DĂ©couvert par** : BUILD-002 (Canvas Vivant V2) **Recette** : 1. CrĂ©er `AXIOM/api_.py` avec : ```python from fastapi import APIRouter, WebSocket, WebSocketDisconnect router = APIRouter() _active_connections: list[WebSocket] = [] @router.websocket("/ws/") async def my_ws(ws: WebSocket): await ws.accept() _active_connections.append(ws) try: while True: data = await ws.receive_text() # ... except WebSocketDisconnect: pass finally: if ws in _active_connections: _active_connections.remove(ws) ``` 2. Ajouter dans `server.py` la liste `_TRANCHE_IMPORTS` : ```python ("api_", ""), ``` 3. Le router est inclus automatiquement par la boucle `app.include_router()`. 4. Pour broadcast : `for ws in list(_active_connections): await ws.send_text(json.dumps(payload))` **Fichiers concernĂ©s** : `api_canvas.py` (rĂ©fĂ©rence implĂ©mentation) --- ## đŸ–Œïž Capture Ă©cran / OmniParser / Vision ### S003 — Capture Ă©cran light pour transmission WebSocket (PIL JPEG base64) **DĂ©couvert par** : BUILD-002 (Canvas Vivant V3) **Code minimal** : ```python from PIL import ImageGrab import io, base64 def capture_light(scale: float = 0.4, quality: int = 60) -> str: img = ImageGrab.grab(all_screens=False) new_size = (int(img.width * scale), int(img.height * scale)) img = img.resize(new_size).convert("RGB") buf = io.BytesIO() img.save(buf, format="JPEG", quality=quality, optimize=True) return f"data:image/jpeg;base64,{base64.b64encode(buf.getvalue()).decode('ascii')}" ``` **Stats** : un Ă©cran 4K (3840×2160) → JPEG 1536×864 qualitĂ© 60 → ~110 KB base64 → transmission WS instantanĂ©e. **Pourquoi pas PNG** : trop lourd pour un screenshot photo (~1-2 MB). JPEG 60 = compromis taille/qualitĂ© parfait pour preview. --- ## đŸȘŸ Always-on-top / Window management ### S009 — FenĂȘtre native Windows avec site web embarquĂ© (PyQt6 + WebEngine) **DĂ©couvert par** : BUILD-002 (Vivien 2026-05-01) — V20.1 livrĂ©e et validĂ©e visuellement. **Vision** : afficher **claude.ai** (ou n'importe quel site web) dans une vraie fenĂȘtre Windows native, sans Chrome, toujours visible (always-on-top), Ă  droite de l'Ă©cran. Permet d'avoir "Claude in Chrome" sans dĂ©pendre du navigateur. **Stack** : - **PyQt6** + **PyQt6-WebEngine** (open source, gratuit, MIT) - Install : `pip install PyQt6 PyQt6-WebEngine` (~150 MB une fois pour toutes) - Profil persistant `QWebEngineProfile` → garde cookies/session entre lancements (pas besoin de re-login) **Recette minimale (50 lignes)** : ```python from PyQt6.QtCore import Qt, QUrl from PyQt6.QtWidgets import QApplication, QMainWindow from PyQt6.QtWebEngineWidgets import QWebEngineView from PyQt6.QtWebEngineCore import QWebEngineProfile, QWebEnginePage from pathlib import Path import sys class NativeWebWindow(QMainWindow): def __init__(self, url: str, width: int = 420): super().__init__() self.setWindowFlags( Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint | Qt.WindowType.Tool # pas dans la barre des tĂąches ) # Position : ancrĂ©e Ă  droite screen = QApplication.primaryScreen().availableGeometry() self.setGeometry(screen.right() - width - 10, 30, width, screen.height() - 90) # Profil persistant (cookies/session) storage = Path.home() / ".my_native_app_session" storage.mkdir(exist_ok=True) profile = QWebEngineProfile("MyApp", self) profile.setPersistentStoragePath(str(storage)) profile.setPersistentCookiesPolicy( QWebEngineProfile.PersistentCookiesPolicy.ForcePersistentCookies ) page = QWebEnginePage(profile, self) view = QWebEngineView() view.setPage(page) view.load(QUrl(url)) self.setCentralWidget(view) if __name__ == "__main__": app = QApplication(sys.argv) win = NativeWebWindow("https://claude.ai") win.show() sys.exit(app.exec()) ``` **Bascule auto online/offline** : ```python import socket def is_online(host="claude.ai", port=443, timeout=2): try: with socket.create_connection((host, port), timeout=timeout): return True except (socket.timeout, OSError): return False # Charger URL en ligne ou fallback local url = "https://claude.ai" if is_online() else "http://127.0.0.1:10001/.../offline.html" ``` **Use-cases** : - ✅ Embed claude.ai dans fenĂȘtre OLYMPUS Canvas Vivant (V20.1 livrĂ©e) - ✅ Embed n'importe quel SaaS (Notion, Google Calendar, Linear) en sidebar fixe - ✅ Multi-instances : 1 fenĂȘtre par projet/contexte (chacune avec son storage path) **Avantages vs Chrome `--app=`** : - ✅ Pas de barre d'adresse Chrome au-dessus - ✅ Vraie fenĂȘtre Windows native (pas un onglet Chrome dĂ©guisĂ©) - ✅ ZĂ©ro dĂ©pendance Chrome (marche mĂȘme si Chrome fermĂ©) - ✅ Always-on-top fiable (Chrome a des bugs avec z-order) - ✅ Multi-fenĂȘtres faciles (1 par projet) **Limites** : - ⚠ Install Python + PyQt6 (~150 MB) - ⚠ PremiĂšre fois : login manuel sur le site - ⚠ Pas d'extensions Chrome (Claude in Chrome, Grammarly, etc.) **Fichier de rĂ©fĂ©rence livrĂ©** : `C:\OLYMPUS\AGORA\scripts\canvas_vivant_v20_1_claude_ai.py` (188 lignes) - Frameless · always-on-top · profil persistant · bascule online/offline auto · drag clic-droit · Echap pour fermer **Pattern industrie** : - **Electron** (GitHub 2013) — mĂȘme idĂ©e mais lourd (~150 MB par app) - **Tauri** (Rust 2020) — lighter - **PyQt WebEngine** (Riverbank 2020+) — choix Python, dĂ©jĂ  installĂ© sur ce poste --- ### S004 — Always-on-top fenĂȘtre Chrome via AutoHotkey v2 **DĂ©couvert par** : BUILD-002 (Canvas Vivant V6) **Recette** : 1. Lancer Chrome en mode app : `chrome --app=URL --window-size=W,H --window-position=X,Y --user-data-dir=PATH` 2. Script `.ahk` (AutoHotkey v2) qui dĂ©tecte le titre de la fenĂȘtre et force always-on-top : ```autohotkey #SingleInstance Force SetTitleMatchMode 2 Loop 120 { if WinExist("Canvas Vivant") { WinSetAlwaysOnTop true, "Canvas Vivant" break } Sleep 500 } F12:: WinSetAlwaysOnTop -1, "Canvas Vivant" ; toggle ``` 3. Hotkeys globaux F10 (reposition) F11 (cacher/afficher) F12 (toggle on/off) **Fichier rĂ©fĂ©rence** : `C:\Users\vivie\Desktop\OLYMPUS\đŸȘŸ Canvas Vivant ALWAYS-ON-TOP.ahk` --- ## đŸȘŸ Hooks clavier · Auto-hide · System prompts par app (CLAUDE_PARTOUT) ### S011 — Hook clavier global Windows (Ctrl+Shift+C) via pynput **DĂ©couvert par** : BUILD-002 mission nocturne 2026-05-02 (Phase 4 bis) **Source d'inspiration** : Espanso (Rust) — `espanso-detect/src/win32/` clonĂ© dans `AGORA/REFERENCES_OPENSOURCE/espanso/`. **ProblĂšme** : LGS doit pouvoir ĂȘtre appelĂ© d'un coup depuis n'importe quelle app (style Cmd+Space Mac · Win+G Windows · Cmd+K Cursor). **Solution Python** : lib `pynput` (dĂ©jĂ  installĂ©e 1.8.1, pas besoin admin). ```python from pynput import keyboard HOTKEY_COMBO = {keyboard.Key.ctrl, keyboard.Key.shift, keyboard.KeyCode.from_char('c')} current_pressed = set() def on_press(key): # Normalise ctrl_l/ctrl_r → ctrl if key in (keyboard.Key.ctrl_l, keyboard.Key.ctrl_r): key = keyboard.Key.ctrl elif key in (keyboard.Key.shift_l, keyboard.Key.shift_r): key = keyboard.Key.shift current_pressed.add(key) if HOTKEY_COMBO.issubset(current_pressed): handle_hotkey() # → spawn Claude pour app active def on_release(key): # idem normalisation puis discard ... with keyboard.Listener(on_press=on_press, on_release=on_release) as listener: listener.join() ``` **Fichier de rĂ©fĂ©rence livrĂ©** : `C:\OLYMPUS\AGORA\scripts\lgs_hotkey_listener.py` **Pattern industrie** : - Espanso (Rust + C++) — hook bas niveau via `RegisterHotKey` Win32 API - pynput (Python) — abstraction multi-OS (Windows, macOS, Linux) --- ### S012 — Auto-hide overlay PyQt6 (slide-in/slide-out animĂ©) **DĂ©couvert par** : BUILD-002 mission nocturne 2026-05-02 (LGS-V10.2) **Source d'inspiration** : Pattern barre des tĂąches Windows + PowerToys overlay. **IdĂ©e** : la fenĂȘtre LGS se rĂ©tracte hors Ă©cran (sliver 3px Ă  droite) quand pas utilisĂ©e. Souris approche bord droit → slide-in. Souris quitte → 1.5s grace period → slide-out. ```python from PyQt6.QtCore import QTimer, QPropertyAnimation, QEasingCurve, QPoint from PyQt6.QtGui import QCursor # Setup dans __init__ (aprĂšs tray) self._slide_anim = None self._hide_timer = QTimer(self) self._hide_timer.setSingleShot(True) self._hide_timer.timeout.connect(self._slide_out) self._mouse_check_timer = QTimer(self) self._mouse_check_timer.timeout.connect(self._check_mouse_position) self._mouse_check_timer.start(200) # poll 5×/sec def _check_mouse_position(self): if self.is_pinned: return # mode Ă©pinglĂ© : pas d'auto-hide screen = QApplication.primaryScreen().availableGeometry() cursor_pos = QCursor.pos() is_near_right = cursor_pos.x() >= screen.right() - 15 is_over_window = self.geometry().contains(cursor_pos) if is_near_right or is_over_window: self._hide_timer.stop() self._slide_in() else: if not self._hide_timer.isActive(): self._hide_timer.start(1500) def _slide_in(self): target_x = screen.right() - WIDTH - MARGIN_RIGHT self._animate_to(target_x, 200, QEasingCurve.Type.OutCubic) def _slide_out(self): target_x = screen.right() - 3 # sliver 3px self._animate_to(target_x, 300, QEasingCurve.Type.InCubic) def _animate_to(self, target_x, duration, easing): if self._slide_anim and self._slide_anim.state() == QPropertyAnimation.State.Running: self._slide_anim.stop() anim = QPropertyAnimation(self, b"pos") anim.setDuration(duration) anim.setStartValue(QPoint(self.x(), self.y())) anim.setEndValue(QPoint(target_x, self.y())) anim.setEasingCurve(easing) anim.start() self._slide_anim = anim ``` **Toggle pin** : si bouton 📌 cliquĂ© (pinned=True), `_check_mouse_position` retourne tĂŽt → reste visible. **Fichier de rĂ©fĂ©rence livrĂ©** : `C:\OLYMPUS\AGORA\scripts\canvas_vivant_v20_1_claude_ai.py` lignes 369-440. --- ### S013 — Subprocess Claude.exe avec timeout + windowsHide (pattern Cline) **DĂ©couvert par** : BUILD-002 mission nocturne 2026-05-02 **Source d'inspiration** : Cline (`src/core/hooks/HookProcess.ts`) — pattern spawn avec timeout + cleanup. **IdĂ©e** : amĂ©liorer S008 avec : - `creationflags=0x08000000` (CREATE_NO_WINDOW Windows) → pas de console qui flash - `timeout` propre avec auto-kill - Decode robuste UTF-8 (dĂ©jĂ  en S008) ```python import subprocess, os def spawn_claude_app(claude_exe: str, system_prompt: str, app_name: str, timeout_s: int = 90): """Spawn 1 Claude dĂ©diĂ© Ă  app_name. Retourne reply markdown.""" full_prompt = f"Tu es Claude-{app_name}, l'assistant Vivien. {system_prompt}" env = os.environ.copy() env['PYTHONIOENCODING'] = 'utf-8' env['PYTHONUTF8'] = '1' env['LANG'] = 'fr_FR.UTF-8' creation_flags = 0x08000000 if os.name == 'nt' else 0 # CREATE_NO_WINDOW try: result = subprocess.run( [claude_exe, "--print", full_prompt], capture_output=True, text=False, timeout=timeout_s, env=env, creationflags=creation_flags, ) # decode_safe (cf. S008) for enc in ('utf-8', 'cp65001', 'cp1252', 'latin-1'): try: return result.stdout.decode(enc).strip() except UnicodeDecodeError: continue return result.stdout.decode('utf-8', errors='replace').strip() except subprocess.TimeoutExpired: return f"[TIMEOUT aprĂšs {timeout_s}s]" ``` **DiffĂ©rences vs S008** : - ✅ `creation_flags=CREATE_NO_WINDOW` — pas de console qui flash sur Windows - ✅ Pattern rĂ©utilisable pour spawn par app (Claude-Excel, Claude-Word, etc.) --- ### S014 — System prompts par app (config JSON par process .exe) **DĂ©couvert par** : BUILD-002 mission nocturne 2026-05-02 (Phase 4 ter) **Source d'inspiration** : Open Interpreter (`computer_use/loop.py`) — SYSTEM_PROMPT dynamique par OS. **IdĂ©e** : 1 fichier JSON, key = nom du process Windows (`EXCEL.EXE`, `WINWORD.EXE`, ...), value = system prompt + mĂ©tadonnĂ©es. **Fichier livrĂ©** : `C:\OLYMPUS\MNEMOSYNE\07_PREFS\lgs_system_prompts.json` (12 apps + default). **Format** : ```json { "EXCEL.EXE": { "name": "Claude-Excel", "icon": "📊", "system_prompt": "Tu es Claude-Excel, l'assistant dĂ©diĂ© de Vivien...", "deep_integration": false } } ``` **Usage** : ```python import json from pathlib import Path PROMPTS_PATH = Path("C:/OLYMPUS/MNEMOSYNE/07_PREFS/lgs_system_prompts.json") with PROMPTS_PATH.open(encoding="utf-8") as f: PROMPTS = json.load(f) def get_prompt_for_app(process_name: str) -> dict: """Retourne config + prompt pour un .exe. Fallback sur _default.""" return PROMPTS.get(process_name, PROMPTS["_default"]) # Usage dans listener Ctrl+Shift+C info = get_active_window() # → {"process": "EXCEL.EXE", ...} config = get_prompt_for_app(info["process"]) prompt_full = config["system_prompt"] + " " + user_question reply = spawn_claude_app(claude_exe, prompt_full, config["name"]) ``` **Apps couvertes (V1)** : Excel, Word, PowerPoint, Outlook, VS Code, Chrome, Notepad, Notepad++, Steam, Spotify, Discord, Explorer, default. **Pattern industrie** : - Open Interpreter — SYSTEM_PROMPT par OS - MS Copilot Office — system prompt par app Microsoft - Apple Intelligence — Writing Tools per-context --- ## 📚 MĂ©ta-pattern — extraction de ressources opensource ### S015 — Catalogue exhaustif d'inspirations open source (BIBLE pattern) **DĂ©couvert par** : BUILD-002 mission Ă©tendue 2026-05-02 (matin) **Demande Vivien** : *"il faut rĂ©cupĂ©rer toutes les idĂ©es d'ergonomie mĂȘme si on peut pas copier... extraire toutes les donnĂ©es pertinentes... compiler dans un fichier pour ne pas avoir Ă  tous relire"*. **Pattern** : extraction massive + compilation indexĂ©e pour ne plus avoir Ă  relire les sources. **Recette appliquĂ©e** (9 phases, ~90 min) : 1. **Phase A** : `git clone --depth=1` de 19 repos prioritaires en parallĂšle (~2.6 GB) 2. **Phase B** : `WebFetch` des pages closed-source (Cursor, Apple Intelligence, MS Copilot) 3. **Phase C** : `grep #[0-9A-Fa-f]{6}` pour extraire palettes couleurs des CSS 4. **Phase D** : `grep -E "Ctrl+|Cmd+|hotkey"` pour extraire raccourcis clavier 5. **Phase E** : `grep "animation:|transition:|@keyframes"` pour extraire animations CSS 6. **Phase F** : `WebSearch` pour articles + vidĂ©os sur closed-source 7. **Phase G** : `curl --max-filesize 5MB` pour tĂ©lĂ©charger screenshots/GIFs README 8. **Phase H** : compilation `BIBLE_RESSOURCES_OLYMPUS.md` (~50 KB exhaustif) 9. **Phase I** : crĂ©ation `INDEX_RESSOURCES.md` (~5 KB navigation rapide) **Livrables** : - `MNEMOSYNE/03_HOWTO/BIBLE_RESSOURCES_OLYMPUS.md` (catalogue 22 sources) - `MNEMOSYNE/03_HOWTO/INDEX_RESSOURCES.md` (navigation rapide) - `MNEMOSYNE/03_HOWTO/PATTERNS_EXTRAITS_OPENSOURCE.md` (patterns code dĂ©taillĂ©s) - `AGORA/REFERENCES_OPENSOURCE/` (sources locales 2.6 GB · 19 repos) - `AGORA/REFERENCES_OPENSOURCE/_ASSETS/` (50 fichiers visuels · 8.2 MB) - `AGORA/REFERENCES_OPENSOURCE/_INDEX/` (donnĂ©es brutes pour audit) **Pattern industrie** : - **Swipe file** (collections d'inspirations centralisĂ©es) — copywriters / designers - **Library catalog** (Dewey, LoC) — index lĂ©ger → emplacement source - **Wikipedia model** — un index pointe vers les articles, pas un rĂ©sumĂ© global **Leçons apprises** : - ❌ MĂ©ga-fichier compilĂ© = vite obsolĂšte + paraphrase la source - ✅ Index lĂ©ger + sources locales = toujours Ă  jour + prĂ©cis - ✅ Lazy evaluation : on n'extrait QUE ce qu'on utilise rĂ©ellement aprĂšs - ✅ Le REGISTRE grandit avec ce qui est RÉELLEMENT utilisĂ© (S016+ futurs) **Quand l'appliquer** : - Avant un gros projet : 1× pour cataloguer le state-of-the-art - À mi-projet : enrichir si nouveaux outils sortent **Limites** : - Closed-source → seulement web research indirect - VidĂ©os lourdes (>5 MB) → URLs only - Demande discipline : Ă  chaque feature codĂ©e, ajouter S0NN au REGISTRE --- ## 📩 Imports / Path Windows ### S005 — Path Windows en Python : forward slash OK, sauf pour AppData\Roaming protĂ©gĂ© **DĂ©couvert par** : BUILD-002 **RĂšgle** : - `os.path.exists("C:/Users/...")` marche partout - SAUF dans certains dossiers protĂ©gĂ©s (`AppData\Roaming\Claude\` cf. S001) - En cas de doute : tester `os.access(p, os.R_OK)` avant `subprocess.run([...])` --- ## đŸ›Ąïž Mona Lisa / Snapshots / Backups ### S007 — Rotation snapshots (Mona Lisa) — Ă©viter accumulation infinie **DĂ©couvert par** : BUILD-002 (Vivien 2026-04-28 : "il faudra penser Ă  nettoyer si y a trop de snapshots") **ProblĂšme** : `CERBER/sauvegardes/zips/` accumule des ZIP Ă  chaque modif majeure (avant V2 backend, avant V5, avant V12, etc). En 1 nuit on en a fait 4. À ce rythme, 50 ZIP × 5 MB = 250 MB inutile. **Solution** : script `C:\OLYMPUS\AGORA\scripts\rotate_snapshots.py` : - Garde les **N derniers** snapshots par prĂ©fixe (NEXUS_, NEXUS_DEV_, CERBER_) - DĂ©place les anciens vers `MNEMOSYNE/09_ARCHIVES/snapshots_anciens/` (Mona Lisa : jamais `rm`) - Default N = 5 - Mode `--dry-run` pour preview **Usage** : ```bash python C:/OLYMPUS/AGORA/scripts/rotate_snapshots.py --keep 5 --dry-run # preview python C:/OLYMPUS/AGORA/scripts/rotate_snapshots.py --keep 5 # exĂ©cute ``` **Cron-isable** : Ă  brancher en tĂąche planifiĂ©e Windows (1× par semaine). --- ### S006 — Snapshot ZIP rapide de NEXUS sans dĂ©pendance externe **DĂ©couvert par** : BUILD-002 **Recette** (fonctionne sans `zip` cmd Windows) : ```bash python -c "import shutil; shutil.make_archive('C:/OLYMPUS/.../snapshot_NAME', 'zip', 'C:/OLYMPUS/01_SERVEUR', 'NEXUS')" ``` **Avant TOUT chantier sur NEXUS / NEXUS_DEV : snapshot d'abord** (R4 + Doctrine Mona Lisa). --- ## 📝 Comment ajouter une solution Ă  ce registre 1. Trouve la catĂ©gorie qui correspond (ou crĂ©e-en une nouvelle) 2. NumĂ©ro `S00N` sĂ©quentiel 3. Sections obligatoires : **DĂ©couvert par** · **SymptĂŽme** · **Cause** · **Solution(s)** · **Fichiers concernĂ©s** 4. RĂ©gĂ©nĂ©rer CODEX (`POST /api/codex/regenerate`) pour que les autres chats voient --- ## đŸ€– Roadmap : convertir ce registre en MCP connecteur > Quand le registre fera 50+ entrĂ©es, crĂ©er un connecteur MCP `olympus-registre` exposant : > - `solution_search(query: str)` → cherche dans le registre > - `solution_add(category, title, content)` → ajoute une nouvelle entrĂ©e > - Permet Ă  Claude de **demander des solutions** sans relire tout le registre. --- ## 🌐 Claude embedded per-app / Vision "Claude partout" ### S010 — Claude-partout (Niveau 1 universel · Niveau 2 par app) > **Note numĂ©rotation** : S009 Ă©tait initialement rĂ©servĂ© Ă  cette entrĂ©e par Vivien, mais S009 est dĂ©jĂ  occupĂ© par "FenĂȘtre native PyQt6 + WebEngine" (catĂ©gorie đŸȘŸ). Donc S010 ici, et S009 reste sa rĂ©servation historique pour la brique UI sous-jacente. **DĂ©couvert par** : claude-code (2026-05-01) — formalisation aprĂšs pose du LGS le matin mĂȘme par Vivien. **Vision en 1 phrase** : gĂ©nĂ©raliser le pattern **S008** (1 chat Claude par tuile UI) Ă  TOUTES les applications du PC. Quand Vivien ouvre Excel → Claude-Excel apparaĂźt. Notepad → Claude-Notepad. Steam → Claude-Steam. Comme Claude in Chrome, mais pour TOUTES les apps. **IdĂ©e centrale** : - 1 chose = 1 Claude dĂ©diĂ©, lancĂ© Ă  la demande, mort aprĂšs usage - LGS (Le Grand Superviseur) orchestre, les Claudes-app exĂ©cutent - 2 niveaux : **N1 universel** (overlay gĂ©nĂ©rique sans code par app) · **N2 deep** (intĂ©gration profonde par app prioritaire avec lib Python dĂ©diĂ©e) **Pattern source** : S008 (chat-par-tuile via subprocess `claude.exe --print`) + S009 (fenĂȘtre PyQt6 frameless ancrĂ©e). **Document maĂźtre** : `MNEMOSYNE/06_PROJETS/CLAUDE_PARTOUT/CONCEPTION.md` - 11 sections (pitch · principe · archi · niveaux · Ă©tat de l'art · existant · archi cible ASCII · roadmap · ergo Ă  voler · codes Ă  rĂ©cupĂ©rer · questions ouvertes · sources) - 30+ projets open source rĂ©fĂ©rencĂ©s (Open Interpreter, AnythingLLM, Continue.dev, AutoGen, Cline, Open WebUI, LobeChat, Jan, Flow Launcher, etc.) - Ergonomie volĂ©e Ă  : Apple Intelligence Sequoia, Microsoft Copilot, Cursor, Raycast, Notion AI, Claude in Chrome, ChatGPT Desktop **Stack envisagĂ©e (Phase 2)** : ```python # Pseudo-code endpoint NEXUS /api/claude_partout/spawn @router.post("/api/claude_partout/spawn") async def spawn_claude_for_app(): aw = await get("/api/god/active_window") # dĂ©tecte app devant app_name = aw["exe_name"] # ex: "EXCEL.EXE" sysprompt = f"Tu es l'assistant {app_name} de Vivien. RĂ©ponds court, utile." # Spawn fenĂȘtre PyQt6 ancrĂ©e Ă  droite (rĂ©utilise S009) # Wrapping subprocess claude.exe --print (rĂ©utilise S008) # Kill auto Ă  fermeture app ``` **Roadmap** : - Phase 1 (✅ acquis) : LGS posĂ©, S008 prod, S009 native window, GOD MODE, Chrome MCP pairĂ© - Phase 2 (🎯 next) : N1 universel + raccourci global `Ctrl+Shift+C` + endpoint `/api/claude_partout/spawn` - Phase 3 (đŸ”” backlog) : N2 par app prioritaire (Excel, Outlook, Steam, Chrome, Krita, Notepad++) - Phase 4 (🌙 futur) : autonomie nocturne + API Anthropic + smart reply universel **Parent direct** : S008 (rĂ©f code `api_canvas.py` lignes 308-398). **Brique UI** : S009 (PyQt6 frameless, profil persistant cookies). **Bras exĂ©cuteur** : Open Interpreter (dĂ©jĂ  installĂ©, couplĂ© codex). **Filet offline** : ollama port 11434 + llama3.1 8B (dĂ©jĂ  installĂ©). **Pattern industrie** : - **Sidecar pattern** (Kubernetes 2015) — chaque Claude-app = sidecar de l'app cible - **Per-app assistant** (Microsoft Copilot Office 2023) — modĂšle UX directement applicable - **MCP fan-out** (Anthropic 2024) — chaque app future devient un MCP connector branchĂ© sur LGS **Fichiers concernĂ©s** : - `MNEMOSYNE/06_PROJETS/CLAUDE_PARTOUT/CONCEPTION.md` (ce projet, 535 lignes) - `MNEMOSYNE/06_PROJETS/LE_GRAND_SUPERVISEUR/CONCEPTION.md` (parent direct) - `MNEMOSYNE/06_PROJETS/OLYMPUS/GOD_OLYMPUS.html` §INDEX MODIFICATIONS (entrĂ©e 01/05/2026) - À venir : `01_SERVEUR/NEXUS/AXIOM/api_claude_partout.py` (endpoint Phase 2) --- ## S011 — Windows-MCP clonĂ© et opĂ©rationnel (BÊTA) > ✅ **AJOUTÉ 2026-05-01** par INSTALL-001 **DĂ©couverte** : le repo CursorTouch/Windows-MCP (2M+ users Claude Desktop) est un MCP server stdio prĂȘt Ă  l'emploi via uvx windows-mcp (Python 3.13+). **Path local** : `C:\OLYMPUS\AGORA\connecteurs_externes\windows-mcp\` **Activation** : ajouter au `%APPDATA%\Claude\claude_desktop_config.json` : ```json "windows-mcp": { "command": "uvx", "args": ["windows-mcp"] } ``` **Coexistence avec mode-dieu-ultime** : OUI — pas de conflit, les 2 MCPs servent en stdio sur des canaux diffĂ©rents. **Statut REST cĂŽtĂ© NEXUS** : `GET /api/win/windows_mcp/status` (ne pilote pas Windows-MCP, juste vĂ©rifie le clone). **Pourquoi DOUBLE l'avoir + mode-dieu-ultime** : Windows-MCP est maintenu par une commu active (CursorTouch), update rĂ©guliĂšrement. mode-dieu-ultime reste notre **super connecteur OLYMPUS-spĂ©cifique** avec le wiring Vivien (NEXUS · ports · checks). Les 2 cohabitent. --- ## S012 — OmniParser V2 clonĂ©, weights Ă  tĂ©lĂ©charger > ✅ **AJOUTÉ 2026-05-01** par INSTALL-001 **DĂ©couverte** : Microsoft Research a publiĂ© OmniParser V2 (HF model `microsoft/OmniParser-v2.0`) — vision GUI parser YOLO-icon-detect + Florence2-caption. Permet Ă  un LLM de comprendre n'importe quel screenshot d'Ă©cran sans accessibility tree. **Path local** : `C:\OLYMPUS\AGORA\connecteurs_externes\omniparser\` **Endpoints NEXUS exposĂ©s** : - `GET /api/vision/omniparser/status` — diagnostic complet (weights · torch · cuda) - `POST /api/vision/parse` `{image_path, box_threshold, iou_threshold}` — appel parser **Reste Ă  faire pour activation complĂšte** : 1. `pip install torch torchvision easyocr ultralytics transformers accelerate paddleocr paddlepaddle` (~3 GB) 2. TĂ©lĂ©charger les weights : `huggingface-cli download microsoft/OmniParser-v2.0 --local-dir omniparser/weights/` (~500 MB) 3. Tester : `POST /api/vision/parse {"image_path": "F:\\screenshot.png"}` **Cas d'usage attendus** : - Comprendre un Ă©cran de jeu (qui ne donne pas l'accessibility tree) - Parser le DOM d'une app native sans pywin32 (Krita, photoshop, etc.) - Cliquer sur un bouton "vu" plutĂŽt que "selectĂ© par UIA" **Limitations connues** : - NĂ©cessite GPU NVIDIA pour latence acceptable (CPU = ~30s par image) - ModĂšles tĂ©lĂ©chargĂ©s depuis HF (refus abonnements respectĂ© : HF est gratuit) --- ## S078 — Super god mod ultime v2.1 enrichi (ENHANCE-GOD-001) > ✅ **AJOUTÉ 2026-05-01** par claude-ENHANCE-GOD-001 **Contexte** : `mode_dieu_ultime_v2.py` Ă©tait en PREVIEW (75 wrappers HTTP NEXUS). Il manquait les imports Python natifs des 12 `tools_extras` + les bridges pour Whisper/Piper TTS/OpenWakeWord/ffmpeg/ImageMagick/Open Interpreter. Mission : finaliser le super-connecteur. **Path canonique** : `C:\OLYMPUS\AGORA\connecteurs_maison\mode-dieu-ultime\mode_dieu_ultime_v2.py` **Doctrine appliquĂ©e** : - Mona Lisa : v1 `mode_dieu_ultime.py` **inchangĂ©**, PREVIEW snapshotĂ© dans `99_BACKUP/mode_dieu_ultime_v2.py.PRE-ENHANCE-GOD-001.bak` - Append-only : v2 rĂ©utilise l'instance FastMCP de v1 + ajoute des `@mcp.tool()` au-dessus - Imports `tools_extras` enveloppĂ©s dans `_try_import_extra()` → libs optionnelles, jamais de crash si une lib manque **Architecture finale (v2.1)** : ``` v1 mode_dieu_ultime → 26 tools natifs (pyautogui/uia/win32/psutil) + tools_extras (12 modules) → ~25 wrappers MCP (audio/notif/clipboard/webcam/ scanner/BT/USB/monitors/window-mgmt/hash/power/sniff) + bridges NEXUS → ~85 wrappers (winmcp UIA · vision OmniParser · voix Whisper/Piper/Wakeword · ffmpeg · ImageMagick · Open Interpreter · WiFi · BT/USB · Box · LAN · speedtest · eBay · LBC · OBS · YouTube · gaming · foobar2000 · VLC · Tailscale · Discord) ───────────────────────────────────────────────────────────────── Total ≈ 140 tools dans une seule instance MCP ``` **Tools de diagnostic ajoutĂ©s** : - `extras_status()` — Ă©tat import des 12 modules `tools_extras` (ok/error dĂ©tail) - `v2_inventory()` — inventaire complet par catĂ©gorie + skipped + extras_status_summary **Skipped (out-of-scope ENHANCE-GOD)** : - Spotify (Vivien prĂ©fĂšre foobar2000) - LangChain / LlamaIndex / agents / web automation (pas du contrĂŽle PC, restent dans NEXUS REST) **Comment activer** : modifier `claude_desktop_config.json` : ```json "mode-dieu-ultime-v2": { "command": "F:\\\\OLYMPUS\\\\DEPENDENCIES\\\\python\\\\python.exe", "args": ["F:\\\\OLYMPUS\\\\AGORA\\\\connecteurs_maison\\\\mode-dieu-ultime\\\\mode_dieu_ultime_v2.py"] } ``` ⚠ Si v2 lancĂ© : dĂ©sactiver v1 (sinon collision FastMCP mĂȘme nom). **Limitation observĂ©e** : test `python compile` formel non effectuĂ© dans cette session car le mount sandbox Linux gardait un cache figĂ© du fichier d'origine. Validation visuelle rĂ©alisĂ©e (130 occurrences `"""` paires + structure cohĂ©rente). Vivien doit relancer Claude Desktop pour test live. **Rollback** : copier `99_BACKUP/mode_dieu_ultime_v2.py.PRE-ENHANCE-GOD-001.bak` → `mode_dieu_ultime_v2.py`. --- --- _Migre F:->C: par docs_portability_light 2026-05-10_