Merlya - AI-powered infrastructure assistant
Project description
Merlya
AI-powered infrastructure assistant for DevOps & SysAdmins
Aperçu
Merlya est un assistant CLI autonome qui comprend le contexte de votre infrastructure, planifie des actions intelligentes et les exécute en toute sécurité. Il combine un SmartExtractor (LLM + regex hybride) pour extraire les hosts des requêtes en langage naturel, un pool SSH sécurisé, et une gestion d'inventaire simplifiée.
Fonctionnalités clés
- Commandes en langage naturel pour diagnostiquer et remédier vos environnements
- Architecture spécialistes :
MerlyaAgentdélègue aux spécialistes (diagnostic, exécution, sécurité) selon la demande - Pool SSH async avec MFA/2FA, jump hosts et SFTP
- Inventaire
/hostsavec import intelligent (SSH config, /etc/hosts, Ansible, TOML, CSV) - Modèles brain/fast : brain pour le raisonnement complexe, fast pour les décisions rapides
- Pipelines IaC : Ansible, Terraform, Kubernetes, Bash avec HITL obligatoire
- Élévation explicite : configuration sudo/doas/su par host (pas d'auto-détection)
- Sécurité by design : secrets dans le keyring, validation Pydantic, détection de boucles
- Observabilité : métriques in-memory + circuit breaker / retry (
/metrics) - i18n : français et anglais
- Intégration MCP pour consommer des tools externes (GitHub, Slack, custom) via
/mcp
Architecture
┌─────────────────────────────────────────────────────────────────────────────┐
│ USER INPUT │
│ "Check disk on web-01 via bastion" │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ SMART EXTRACTOR │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Fast Model │───▶│ Regex │───▶│ Hosts │ │
│ │ (semantic) │ │ Patterns │ │ Inventory │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ Output: hosts=[web-01], via=bastion, context injected │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ MERLYA AGENT │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ System prompt guides delegation decision (no separate classifier) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │Diagnostic│ │Execution │ │Security │ │ Query │ │
│ │Specialist│ │Specialist│ │Specialist│ │Specialist│ │
│ │read-only │ │HITL+pipes│ │sec audits│ │inventory │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ SECURITY LAYER │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Keyring │ │ Elevation │ │ Loop │ │
│ │ Secrets │ │ Explicit │ │ Detection │ │
│ │ @secret-ref │ │ (per-host) │ │ (5+ repeat) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ SSH POOL │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Connection │ │ Jump Host │ │ MFA │ │
│ │ Reuse │ │ Support │ │ Support │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ PERSISTENCE │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Hosts │ │ Sessions │ │ Audit │ │ Raw Logs │ │ Messages │ │
│ │ Inventory│ │ Context │ │ Logs │ │ (TTL) │ │ History │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ SQLite + Keyring │
└─────────────────────────────────────────────────────────────────────────────┘
Installation (utilisateurs finaux)
pip install merlya
merlya
Installation Docker
# Copier et configurer les variables d'environnement
cp .env.example .env
# Éditer .env avec vos clés API
# Lancer le conteneur
docker compose up -d
# Mode développement (code source monté)
docker compose --profile dev up -d
Configuration SSH pour Docker :
Le conteneur monte votre répertoire SSH local. Par défaut, il utilise $HOME/.ssh.
Dans les environnements CI/CD où $HOME peut ne pas être défini, vous devez explicitement définir SSH_DIR :
# Via variable d'environnement
SSH_DIR=/root/.ssh docker compose up -d
# Ou dans votre fichier .env
SSH_DIR=/home/jenkins/.ssh
Permissions requises :
- Répertoire SSH :
700(rwx pour propriétaire uniquement) - Clés privées :
600(rw pour propriétaire uniquement)
Voir .env.example pour la documentation complète des variables.
Premier démarrage
- Sélection de la langue (fr/en)
- Configuration du provider LLM (clé stockée dans le keyring)
- Scan local et import d’hôtes (SSH config, /etc/hosts, inventaires Ansible)
- Health checks (RAM, disque, LLM, SSH, keyring, web search)
Exemples rapides
> Check disk usage on web-prod-01
> /hosts list
> /ssh exec db-01 "uptime"
> /model show
> /metrics
> /variable set region eu-west-1
> /mcp list
Syntaxe des targets :
@web-01→ lookup inventaire (hostname + username résolus depuis la base)ubuntu@192.168.1.5→ utilisateur SSH explicite + IP192.168.1.5→ IP directe (username depuis l'inventaire si connu)@db-password→ référence secret dans le keyring (résolu à l'exécution)
Sécurité
Secrets — jamais exposés au LLM
Les secrets (mots de passe, tokens, clés API) sont stockés dans le keyring système (macOS Keychain, Linux Secret Service) et référencés par @nom-secret :
> Connect to MongoDB with @db-password
# Le LLM voit "@db-password", jamais la valeur réelle
# Résolution uniquement au moment de l'exécution
# Logs : "mongo -p ***", jamais la vraie valeur
HITL — confirmation obligatoire
Toute opération destructive (restart, écriture fichier, installation) requiert une confirmation explicite avant exécution. L'ExecutionSpecialist ne peut pas contourner ce mécanisme.
Élévation de privilèges
L'élévation (sudo, doas, su) est toujours explicite — jamais auto-détectée. Elle se configure par host et les mots de passe sont stockés dans le keyring sous elevation:hostname:password.
Détection de boucles
Le ToolCallTracker détecte les patterns répétitifs (même commande 3+ fois, alternance A-B-A-B) et stoppe l'exécution automatiquement.
Configuration
- Fichier utilisateur :
~/.merlya/config.yaml(langue, modèle, timeouts SSH, UI). - Clés API : stockées dans le keyring. Fallback en mémoire avec avertissement.
- Variables d'environnement utiles :
| Variable | Description |
|---|---|
OPENROUTER_API_KEY |
Clé OpenRouter (provider par défaut) |
ANTHROPIC_API_KEY |
Clé Anthropic |
OPENAI_API_KEY |
Clé OpenAI |
MISTRAL_API_KEY |
Clé Mistral |
GROQ_API_KEY |
Clé Groq |
MERLYA_ROUTER_FALLBACK |
Modèle LLM de fallback pour le routage |
Installation pour contributeurs
git clone https://github.com/m-kis/merlya.git
cd merlya
python -m venv .venv
source .venv/bin/activate # ou .venv\\Scripts\\activate sous Windows
pip install -e ".[dev]" # Dépendances de dev
merlya --version
pytest tests/ -v
Qualité et scripts
| Vérification | Commande |
|---|---|
| Lint | ruff check merlya/ |
| Format (check) | ruff format --check merlya/ |
| Type check | mypy merlya/ |
| Tests + coverage | pytest tests/ --cov=merlya --cov-report=term-missing |
| Sécurité (code) | bandit -r merlya/ -c pyproject.toml |
| Sécurité (dépendances) | pip-audit -r <(pip freeze) |
Principes clés : DRY/KISS/YAGNI, SOLID, SoC, LoD, pas de fichiers > ~600 lignes, couverture ≥ 80%, commits conventionnels (cf. CONTRIBUTING.md).
CI/CD
.github/workflows/ci.yml: lint + format check + mypy + tests + sécurité (Bandit + pip-audit) sur runners GitHub pour chaque PR/push..github/workflows/release.yml: build + release GitHub + publication PyPI via trusted publishing, déclenché sur tagv*ouworkflow_dispatchpar un mainteneur (pas de secrets sur les PR externes).- Branche
mainprotégée : merge via PR, CI requis, ≥1 review, squash merge recommandé.
Documentation
📚 Documentation complète : https://merlya.m-kis.fr/
Fichiers locaux :
- docs/architecture.md : architecture et décisions
- docs/commands.md : commandes slash
- docs/configuration.md : configuration complète
- docs/tools.md : tools et agents
- docs/ssh.md : SSH, bastions, MFA
- docs/extending.md : extensions/agents
- SECURITY.md : modèle de sécurité et signalement de vulnérabilités
Contribuer
- Lisez CONTRIBUTING.md pour les conventions (commits, branches, limites de taille de fichiers/fonctions).
- Respectez le CODE_OF_CONDUCT.md.
- Les templates d’issues et de PR sont disponibles dans
.github/.
Sécurité
Consultez SECURITY.md. Ne publiez pas de vulnérabilités en issue publique : écrivez à security@merlya.fr.
Licence
MIT avec Commons Clause. La Commons Clause interdit la vente du logiciel comme service hébergé tout en autorisant l’usage, la modification et la redistribution.
Made by M-KIS
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file merlya-0.8.5.tar.gz.
File metadata
- Download URL: merlya-0.8.5.tar.gz
- Upload date:
- Size: 1.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c49211e32e494485cbc692695fb9b5c641bbc4473a3008077d7d78afe3372d07
|
|
| MD5 |
f1677749aa898178163f0f9f1a120b52
|
|
| BLAKE2b-256 |
5e89c27eaff71e98b7538f58e8f7066b91123d829bc7bf3fc7743117dbd35fec
|
Provenance
The following attestation bundles were made for merlya-0.8.5.tar.gz:
Publisher:
release.yml on m-kis/merlya
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
merlya-0.8.5.tar.gz -
Subject digest:
c49211e32e494485cbc692695fb9b5c641bbc4473a3008077d7d78afe3372d07 - Sigstore transparency entry: 976604589
- Sigstore integration time:
-
Permalink:
m-kis/merlya@dec1403d693d6f0cd762ec454e8c18d62a04db5f -
Branch / Tag:
refs/tags/v0.8.5 - Owner: https://github.com/m-kis
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
self-hosted -
Publication workflow:
release.yml@dec1403d693d6f0cd762ec454e8c18d62a04db5f -
Trigger Event:
push
-
Statement type:
File details
Details for the file merlya-0.8.5-py3-none-any.whl.
File metadata
- Download URL: merlya-0.8.5-py3-none-any.whl
- Upload date:
- Size: 592.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cd664832f1281718d8901f59c6edda815d0e99caabbba340171f0281bfcf5bd9
|
|
| MD5 |
e596bfc69caf566335c1caad0d6249b6
|
|
| BLAKE2b-256 |
7d50bad815aa1ffa65153f1d6bffa57402f6e5db8ab010cc05b914bc38e0b572
|
Provenance
The following attestation bundles were made for merlya-0.8.5-py3-none-any.whl:
Publisher:
release.yml on m-kis/merlya
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
merlya-0.8.5-py3-none-any.whl -
Subject digest:
cd664832f1281718d8901f59c6edda815d0e99caabbba340171f0281bfcf5bd9 - Sigstore transparency entry: 976604590
- Sigstore integration time:
-
Permalink:
m-kis/merlya@dec1403d693d6f0cd762ec454e8c18d62a04db5f -
Branch / Tag:
refs/tags/v0.8.5 - Owner: https://github.com/m-kis
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
self-hosted -
Publication workflow:
release.yml@dec1403d693d6f0cd762ec454e8c18d62a04db5f -
Trigger Event:
push
-
Statement type: