README.md
Rama main · réplica de lectura del repositorio original.
# Lyra
[](https://github.com/amineutron/lyra/actions/workflows/tests.yml) [](LICENSE) [](https://www.python.org/downloads/) [](https://codespaces.new/amineutron/lyra)
**Documentation : [amineutron.github.io/lyra](https://amineutron.github.io/lyra/)** (installation, matériel, sécurité et flux de données, ajouter son propre serveur MCP, FAQ, mesures).
**English summary.** Lyra is a voice-driven DevOps assistant that runs locally by default: Ollama models, faster-whisper speech-to-text, Piper text-to-speech, a three-tier RAG over MCP tool specs, and a resident daemon with text, voice and web clients. It drives KVM virtual machines, backups and home devices through MCP servers, and never runs a sensitive action without a human confirmation. AGPL-3.0 with a commercial option; French-first interface. What is captured and what leaves the machine: [docs/user/DATA_FLOWS.en.md](docs/user/DATA_FLOWS.en.md) (French: [DATA_FLOWS.md](docs/user/DATA_FLOWS.md)).
Assistant vocal DevOps **local par défaut** — pas d'API cloud, pas de facture, sorties réseau optionnelles et [listées](docs/user/DATA_FLOWS.md). Tu lui parles (ou tu lui écris) en français, il gère tes VMs, tes backups, ta TV, tes lumières. Tout tourne sur ta machine : LLM via Ollama, reconnaissance vocale, synthèse vocale.
Née comme copilote pour gérer un homelab (KVM, backups, domotique), Lyra s'appuie sur un pipeline RAG à 3 niveaux + un routage à base de règles pour éviter d'interroger un LLM à chaque requête triviale — résultat : des réponses en dessous de la seconde une fois le démon chaud.
## Démo, en vrai

Enregistrée sur le démon réel avec [`docs/demo/record.sh`](docs/demo/record.sh) : une requête de lecture, puis « supprime la vm test-vm » que Lyra propose comme action destructive et annule quand on répond non.

L'animation jouée à la fin de `install.sh` (`intro/lyra_intro.sh`) : elle sonde la vraie installation (runtime, GPU, modèles Ollama, serveurs MCP, sudoers, alias, service de suivi). Régénérée avec [`docs/demo/record_intro.sh`](docs/demo/record_intro.sh).
## Un aperçu
Lyra a une petite sœur web : neutroncore, un hub PWA qui permet de discuter avec elle depuis le navigateur (mobile compris), avec le même thème visuel — palette or/rose "réacteur" reprise directement dans l'installeur en ligne de commande.
!neutroncore
## Fonctionnalités
- **VMs KVM** : démarrer, arrêter, cloner, snapshots, exécution de commandes, vérification de clones
- **Backups** : status, liste, création, restauration, vérification, nettoyage (Timeshift/Borg/snapshot)
- **Domotique** : TV Philips (power, volume, Ambilight, apps, YouTube Premium sans pubs via ADB), lumières Hue (couleurs, scènes, groupes), Chromecast (catt), home cinéma Denon
- **Mode vocal** : STT (faster-whisper) + TTS (Piper), 6 voix françaises au choix
- **Mode performance** : domotique sans confirmation (latence < 200ms) — jamais pour VM/backup
- **Human-in-the-loop** : confirmation obligatoire avant toute action sensible, todo-list pour les actions multiples
- **Opérations async** : clone VM, backups longs exécutés en arrière-plan avec notification
- **Démon résident** : sessions multiples, pipeline RAG déjà chaud, ~0.3-1s par requête une fois lancé
## Démo
```
Toi: clone preprod-09 vers sandbox-01 et sandbox-02
[i] Todo list: 2 actions proposees
==================================================
[1] vm_clone -> sandbox-01
[2] vm_clone -> sandbox-02
==================================================
Executer ? [T]out / [1] par 1 / [n]on : t
[i] [1/2] vm_clone -> sandbox-01
[+] Operation lancee en arriere-plan.
[i] [2/2] vm_clone -> sandbox-02
[+] Operation lancee en arriere-plan.
[+] Todo list terminee: 2/2 actions
```
**Aucune donnée client n'est utilisée dans les démonstrations.** Les démos tournent sur une entreprise fictive, générée par [`scripts/synthetic_demo_data.py`](scripts/synthetic_demo_data.py) (utilisateurs, parc de postes et serveurs, VM, sauvegardes, tickets, cohérents entre eux, toujours identiques pour une graine donnée, adresses réservées à la documentation). Après une démo ou une mission, `lyra --purge` efface et vérifie ce que Lyra a gardé en clair.
## Prérequis
| Composant | Minimum | Confortable |
|---|---|---|
| Système | Fedora 42, Ubuntu 24.04 ou Arch (testés en VM, [protocole](docs/user/VM_INSTALL_TESTS.md)) | idem |
| Python | 3.11 | 3.12 |
| RAM | 8 Go | 16 Go |
| GPU | aucun : les modèles par défaut (`qwen2.5-coder:0.5b`, `llama3.2:1b`) tournent sur CPU ou sur un Ollama distant (`--ollama-host`) | NVIDIA avec 4 Go de VRAM (`pip install ".[gpu]"` pour faster-whisper sur CUDA) |
| Disque | 3 Go (modèles, voix, dépendances) | 10 Go avec les modèles « production » 7b et 3b |
| Audio | micro et sortie son pour le mode vocal ; rien pour le mode texte | |
Les valeurs par défaut sont volontairement petites ; les modèles plus gros sont commentés dans `config.yaml.example`.
Installation sans carte graphique vérifiée le 2026-09-13 : `pip install .` dans un conteneur `python:3.12-slim` n'installe aucun paquet `nvidia-*` (48 paquets, faster-whisper sur CPU via ctranslate2) et `lyra --help` répond.
## Essayer sans rien installer
Trois chemins d'évaluation en mode texte, sans toucher à ta machine : un
Codespace GitHub branché sur un Ollama distant, une pile de conteneurs
(`docker-compose.sovereign.yml` : Ollama, Lyra, l'API mcp-tracking et un MCP
d'exemple, profils `cpu` et `gpu`), ou le vrai installeur rejoué dans une VM
propre. Mode d'emploi : [deploy/eval/README.md](deploy/eval/README.md).
```bash
podman compose -f docker-compose.sovereign.yml --profile cpu up -d --build
podman compose -f docker-compose.sovereign.yml exec lyra lyra "liste les taches"
```
## Démarrage rapide
```bash
git clone https://github.com/amineutron/lyra.git && cd lyra
./installer/install.sh
```
Le paquet Python seul (client, démon, règles, bancs) s'installe aussi depuis PyPI, sans les modèles ni les serveurs MCP : `uv tool install lyra-assistant` puis `lyra --version` (après publication ; en attendant : `uv tool install git+https://github.com/amineutron/lyra`). L'installeur reste le chemin complet.
L'installeur (TUI Rich interactif, ou `--app` pour une version graphique locale) détecte ta distro (Fedora/Debian/Arch), installe les dépendances système, crée le venv, télécharge Piper + une voix française, installe le client Ollama et pull deux modèles légers par défaut — **`qwen2.5-coder:0.5b`** (Apache-2.0) et **`llama3.2:1b`** (« Built with Llama », [licence](docs/licenses/LLAMA-3.2-COMMUNITY-LICENSE.txt)), environ **4 Go de VRAM** au total. Les voix Piper et leurs licences sont listées dans [VOICES.md](VOICES.md). Ça tourne sans GPU dédié : `--ollama-host <ip>` pointe vers une machine distante qui héberge Ollama (validé le 2026-08-24 en conditions réelles sur 3 VMs Fedora, Ubuntu et Arch sans GPU : voir [docs/user/VM_INSTALL_TESTS.md](docs/user/VM_INSTALL_TESTS.md)).
Aucune commande à copier-coller à la main pour les permissions sudo — l'installeur génère lui-même les règles `sudoers` pour ton utilisateur, pas un nom codé en dur.
### Utilisation
```bash
lyra # mode texte interactif
lyra --vocal # mode vocal (STT/TTS)
lyra -p # mode performance (domotique sans confirmation)
lyra "demarre preprod-09" # one-shot, sans interface
lyra -y "liste mes VMs" # one-shot, confirmation auto
```
## Architecture
Chaque requête traverse le démon `lyra-daemon` (socket Unix, pipeline RAG déjà chargé en mémoire, plusieurs sessions en parallèle). Le RAG à 3 niveaux (registry / capabilities / parameters dans ChromaDB) retrouve les outils MCP pertinents ; un système de règles déterministes (`lyra/rules/`) court-circuite EPHAISTOS pour les cas fréquents et fiables ; sinon EPHAISTOS extrait les arguments (avec un encodage TOON qui compresse les specs d'environ 40 % — sauté si le modèle fait moins d'1B, il ne le comprend pas encore) ; LYRA porte la conversation et le ton ; HESTIA exécute et route vers le bon serveur MCP.
```mermaid
flowchart LR
subgraph ENTREE["Entree utilisateur"]
direction TB
USER(["Texte ou voix"])
STT["faster-whisper (STT)"]
end
subgraph DAEMON["lyra-daemon (socket unix, multi-session)"]
direction TB
PRE["SlangNormalizer + ContextInjector"]
IC{"IntentClassifier"}
PRE --> IC
end
subgraph RAG["RAG Enhanced"]
direction TB
R3["RAG3Tier (ChromaDB)<br/>registry / capabilities / parameters"]
EMB["embeddings<br/>all-MiniLM-L6-v2"]
FUS["fallback<br/>BM25 + Semantic + RRF"]
RULES{"rules.detect()<br/>vm, backup, hue, denon,<br/>tv, catt, tracking,<br/>ironman, screen_manager"}
R3 --> EMB
R3 --> RULES
end
subgraph MODELES["Modeles locaux (Ollama)"]
direction TB
TOON["encodage TOON<br/>(si modele >= 1B)"]
EPH["EPHAISTOS<br/>qwen2.5-coder:0.5b"]
LYR["LYRA<br/>llama3.2:1b"]
TOON --> EPH
end
subgraph EXEC["HESTIA - execution MCP"]
direction TB
HES["HESTIA"]
M1["fedora-agents"]
M2["hue-mcp"]
M3["pylips-mcp"]
M4["denon-mcp"]
M5["catt-mcp"]
M6["tracking"]
HES --> M1
HES --> M2
HES --> M3
HES --> M4
HES --> M5
HES --> M6
end
subgraph SORTIE["Sortie"]
direction TB
TTS["Piper TTS"]
TXT["Reponse texte"]
end
USER --> PRE
USER -. vocal .-> STT
STT --> PRE
IC -->|demande| R3
IC -->|info / discussion| LYR
RULES -->|match : court-circuit| HES
RULES -->|pas de match| TOON
EPH --> HES
R3 -. si RAG3Tier desactive .-> FUS
FUS --> RULES
HES --> LYR
LYR --> TTS
LYR --> TXT
```
## Les mascottes et les divinités — la direction artistique
Lyra emprunte sa palette (or `#f6c177`, rose `#eb6f92`, "thème réacteur") à neutroncore — les deux partagent la même identité visuelle. Ce n'est pas juste un logo : la ligne de commande hérite du même soin.
**Les modèles portent des noms de divinités grecques, pas par hasard :**
- **HESTIA** — déesse du foyer, gardienne de la maison. Dans le code : *"Elle exécute les tâches domestiques (MCP) avec soin."* C'est elle qui parle aux serveurs MCP et garde la maison (le homelab) en ordre.
- **EPHAISTOS** — dieu forgeron, artisan des dieux. Il forge les arguments à partir des specs MCP brutes — le même patronyme que le projet "forge d'agents" prévu pour la suite de Lyra.
- **LYRA** — l'instrument d'Apollon, la voix et l'harmonie. C'est elle qui porte le dialogue, le ton, la personnalité.
**Les mascottes de l'installeur** : 30 créatures ASCII animées (`installer/assets/mascots.json`), réparties en deux familles selon la vitesse d'une étape — *fast* (bolt, comet, atom, pinwheel, radar, rocket, firefly, spark, dart…) pour les étapes rapides, *slow* (owl, cat, turtle, golem, whale, wizard, moon…) pour celles qui prennent leur temps. Chacune a un rôle écrit à la main :
> *owl — "Le hibou : observe longtemps avant de répondre."*
> *comet — "Toujours en mouvement, la traînée raconte d'où elle vient."*
> *golem — "Le golem : la pierre qui pense. Seuls ses yeux bougent."*
Une mascotte est piquée au hasard dans la famille correspondante à chaque étape de l'installeur — une manière de rendre un process forcément un peu long (téléchargements, pip, modèles) plus vivant à regarder.
## Métriques
| Mesure | Valeur |
|---|---|
| Tests unitaires et installeur | **1 051** verts ([CI](https://github.com/amineutron/lyra/actions/workflows/tests.yml), `uv run pytest tests/unit tests/installer`) |
| Suite complète (unit + intégration + e2e) | **1 187** verts, 1 ignoré (`make test`) |
| Latence du pipeline | mesures datées et rejouables dans [BENCHMARKS.md](BENCHMARKS.md) (`make bench-daemon`) |
| Détection des commandes | **152/152** sur le banc de règles, sans LLM ([BENCHMARKS.md](BENCHMARKS.md), `make bench-regles`) |
| Commandes hors règles, petit modèle | **21/21**, **51/51**, **100/100**, **50/50** et **50/50** sur les cinq jeux de développement (5 serveurs, `qwen2.5-coder:0.5b`), contre 5/21 et 13/51 avant la [boucle d'amélioration](docs/dev/BOUCLE_AMELIORATION.md) ([article](docs/articles/2026-09-boucle-ephaistos.fr.md), [English](docs/articles/2026-09-boucle-ephaistos.en.md)) ([BENCHMARKS.md](BENCHMARKS.md), `make bench-modeles`). Sur un **sixième jeu de 50 formulations tenu à l'écart** (jamais itéré), la configuration finale fait **42/50** ; avec les deux jeux scellés précédents (41/50, 35/50), c'est la fourchette de généralisation à retenir, les jeux itérés ne mesurant que la boucle |
| VRAM (mode expérimental, actuel) | ~4 Go (0.5b + 1b + embeddings) — estimation, non mesurée |
| VRAM (mode production, backup) | ~10.5 Go (7b + 3b + embeddings) — estimation, non mesurée |
| Outils MCP disponibles | **88**, répartis sur 5 serveurs ([MCP_TOOLS.md](docs/user/MCP_TOOLS.md), vérifiable par `make smoke`) |
| TTS (Piper, toutes voix) | latence par voix dans [BENCHMARKS.md](BENCHMARKS.md) (`make bench-tts`) |
| Installeur validé en réel | Fedora, Ubuntu, Arch — sans GPU ([protocole et résultats](docs/user/VM_INSTALL_TESTS.md)) |
Protocole de mesure, machine de référence et format des résultats :
[`benchmarks/README.md`](benchmarks/README.md).
## Intégrations MCP
Catalogue déclaratif (`installer/core/catalog.yaml`), sélectionnable à l'installation :
| MCP | Rôle | Dépôt |
|---|---|---|
| `fedora-agents` | VMs KVM + backups (17 outils) | public |
| `hue-mcp` | Lumières Philips Hue | public |
| `pylips-mcp` | TV Philips (JointSpace + ADB) | public |
| `denon-mcp` | Home cinéma Denon AVR (telnet) | public |
| `catt-mcp` | Cast Chromecast/YouTube | public |
| `tracking` | Suivi des opérations longues | intégré |
Ces dépôts MCP sont publics mais taillés pour ma domotique — le cœur de Lyra (dialogue, RAG, démon, mode texte) fonctionne très bien avec **zéro MCP sélectionné** (testé le 2026-08-24, même protocole). Envie d'écrire ton propre serveur MCP pour ta propre domotique ? Une entrée YAML dans `catalog.yaml` suffit (voir `installer/README.md`).
## Sécurité : ce que le code garantit
| Garantie | Où dans le code | Test |
|---|---|---|
| Confirmation humaine avant toute action ; les outils dangereux (listés, ou annotés `destructiveHint` par leur serveur MCP) ne sont jamais auto-confirmés, même en mode performance ou avec `-y` | [`lyra/core/constants.py`](lyra/core/constants.py) (`DANGEROUS_TOOLS`, `DESTRUCTIVE_TOOLS`), [`lyra/daemon/actions.py`](lyra/daemon/actions.py) (`_should_skip_confirmation`) | [`tests/unit/test_confirm_prompt.py`](tests/unit/test_confirm_prompt.py) |
| Arguments validés par liste blanche avant tout script shell (noms de VM, chemins, commentaires) | [`scripts/async_mcp_wrapper.py`](scripts/async_mcp_wrapper.py), [`lyra/core/validation.py`](lyra/core/validation.py) | [`tests/unit/test_async_wrapper_validation.py`](tests/unit/test_async_wrapper_validation.py) |
| Lecture de l'état réel avant d'agir (read-first) | [`lyra/core/validation.py`](lyra/core/validation.py) (`validate_vm_existence`) | [`tests/unit/rules/`](tests/unit/rules/) |
| Scripts privilégiés copiés en root et autorisés un par un dans `sudoers.d`, jamais de sudo global | [`installer/core/steps/mcps.py`](installer/core/steps/mcps.py) | [`tests/installer/test_mcps_sudoers.py`](tests/installer/test_mcps_sudoers.py) |
| Secrets hors de `config.yaml` (fichier `secrets.yaml` en 0600, jeton GitHub jamais écrit sur disque) | [`secrets.yaml.example`](secrets.yaml.example), [`installer/core/gitauth.py`](installer/core/gitauth.py) | [`tests/installer/test_gitauth.py`](tests/installer/test_gitauth.py) |
| Aucun chemin personnel ni adresse privée dans le dépôt | garde-fou CI ([workflow](.github/workflows/tests.yml)) | [`tests/unit/test_paths.py`](tests/unit/test_paths.py) |
| Versions vérifiables : tag signé, `uv.lock` contrôlé en CI, chaque wheel et sdist publié avec `sbom.json` (CycloneDX) et deux attestations Sigstore (provenance, SBOM) | [`.github/workflows/release.yml`](.github/workflows/release.yml), [procédure](docs/dev/release-process.md) | `gh attestation verify <wheel> --owner amineutron` |
| Local par défaut : aucune sortie réseau sans configuration explicite | [`docs/user/DATA_FLOWS.md`](docs/user/DATA_FLOWS.md) | vérification par `grep` décrite dans le document |
Signaler une faille : [politique de sécurité](https://github.com/amineutron/.github/blob/main/SECURITY.md).
## Configuration
Extrait de `config.yaml` (généré par l'installeur, jamais commité) :
```yaml
models:
ephaistos:
name: "qwen2.5-coder:0.5b" # analyse/arguments — leger, actif par defaut
lyra:
name: "llama3.2:1b" # dialogue/personnalite — leger, actif par defaut
audio:
sample_rate: 48000
silence_duration: 1.0
stt:
model: base
language: fr
tts:
model: fr_FR-upmc-medium
```
## Contribuer
La feuille de route est dans [ROADMAP.md](ROADMAP.md) et les [issues](https://github.com/amineutron/lyra/issues) ; les règles dans [CONTRIBUTING](https://github.com/amineutron/.github/blob/main/CONTRIBUTING.md) et le [CLA](CLA.md).
## Part of the Lyra ecosystem
| Dépôt | Rôle |
|---|---|
| [fedora-agents](https://github.com/amineutron/fedora-agents) | MCP : machines virtuelles KVM et sauvegardes |
| [mcp-tracking](https://github.com/amineutron/mcp-tracking) | MCP + API + tableau de bord des tâches longues |
| [neutroncore](https://github.com/amineutron/neutroncore) | hub PWA du homelab |
| [hue-mcp](https://github.com/amineutron/hue-mcp) | MCP Philips Hue (fork de ThomasRohde/hue-mcp) |
| [pylips-mcp](https://github.com/amineutron/pylips-mcp) | MCP TV Philips |
| [denon-mcp](https://github.com/amineutron/denon-mcp) | MCP ampli Denon |
| [catt-mcp](https://github.com/amineutron/catt-mcp) | MCP Chromecast et DLNA |
## Licence
Lyra est publiée sous **AGPL-3.0** depuis la version 1.1.0 (les versions jusqu'à 1.0.0 restent MIT). Utilisation, étude, modification et redistribution libres à condition de publier vos modifications sous la même licence, y compris en usage réseau. Pour intégrer Lyra dans un produit fermé ou obtenir un support contractuel, une [licence commerciale](COMMERCIAL-LICENSE.md) est proposée. Les contributions sont soumises au [CLA](CLA.md).
La synthèse vocale repose sur [Piper](https://github.com/rhasspy/piper) (GPL-3.0), installé séparément par l'installeur : les deux licences sont compatibles, votre code reste sous AGPL.