Un agent de code 100 % local — privé, sécurisé, extensible — qui rivalise avec un agent cloud sur une machine perso.
Pas d'API cloud. Aucune donnée ne quitte la machine. Le cerveau (MLX/Apple Silicon), les outils, la mémoire, le RAG, et les connecteurs (Gmail, web, MCP) tournent en local.
Étude de cas technique · Architecture · Sécurité · Pour les entreprises
Status : v2.1+ stable · 699 tests · CI à gates (bandit / gitleaks / pip-audit / coverage) · cerveau MLX
Qwen3.6-35B-A3B· client et serveur MCP
La plupart des agents de code envoient ton code et tes données dans le cloud. Klody fait l'inverse : tout s'exécute sur ta machine. Le défi technique — faire d'un modèle local (plus petit que la frontière) un agent fiable — est résolu par l'orchestration, pas par la force brute : un routeur adaptatif, une boucle ReAct qui va au bout, un sandbox isolé, et une discipline de tests/sécurité de niveau production. Le tout extensible via MCP : Klody consomme des serveurs externes (Gmail, web…) et s'expose comme serveur pour d'autres agents.
| 🔒 Privé par conception | 100 % local. Sandbox fichiers multi-racines, fichiers sensibles bloqués partout, anti-SSRF sur le web, commits signés. |
| 🧭 Orchestration, pas brute force | Routeur (easy/medium/hard × 12 types de tâches, F1≈0,85), boucle auto-prolongée, Best-of-N conditionnel, anti-stall. |
| 🔌 Extensible via MCP | Client MCP (consomme Gmail, web, n'importe quel serveur) + serveur MCP (Cline/Zed/Continue consomment Klody). |
| 🧰 Complet | 69 outils, app desktop (Tauri/React, thème clair/sombre/auto), mémoire long terme, RAG livres, retrieval code-aware. |
| 🖥️ Pilote ton environnement | macOS (AppleScript, Spotlight, Raccourcis→HomeKit/Automator, Finder), maison connectée (MQTT : ESP32, Raspberry Pi), automatisation fichiers (renommage, organisation, sauvegarde, synchro). |
| 🔨 Toolsmithing | Klody ne se contente pas d'utiliser des outils, il les fabrique : scripts, CLI, APIs FastAPI, serveurs MCP, workflows, pipelines, plugins Klody, interfaces web — chacun livré avec son test. |
| ⚙️ Ops & génération | Introspection Docker/Kubernetes/Git (lecture seule, mutations gated), SQL SQLite sandboxé, diagrammes UML, scaffolding d'API REST/GraphQL, SDK et repository NoSQL. |
| ✅ Production-grade | 699 tests, coverage 78 %, CI 5 jobs (sécurité + régression + contrat), branch protection + signed commits. |
flowchart TD
U([👤 Utilisateur]) --> UI["🖥️ App desktop · Tauri 2 + React 19<br/>thème clair/sombre/auto"]
UI <-->|WebSocket| API["⚡ FastAPI · :8000"]
API --> ORCH
subgraph ORCH["🧭 Adaptive Orchestrator — boucle ReAct"]
R["Router · easy/medium/hard × 6 task_types"]
L["Boucle auto-prolongée + anti-stall + Best-of-N"]
R --> L
end
ORCH --> TOOLS
ORCH --> MCPC["🔌 Client MCP"]
ORCH --> LLM
subgraph TOOLS["🧰 Outils natifs (69)"]
direction LR
T1["fichiers · sandbox<br/>multi-racines"]
T2["code-aware<br/>tree-sitter + bge-m3"]
T3["github · preview<br/>audio · skills · mémoire"]
T4["macOS · MQTT<br/>automatisation · toolsmithing"]
end
MCPC -->|outils Gmail| GM["📧 Serveur MCP Gmail · :8084"]
MCPC -->|outils Web| WB["🌐 Serveur MCP Web · :8085<br/>lecture seule · anti-SSRF"]
subgraph LLM["🧠 LLM 100% local"]
direction LR
B["MLX cerveau<br/>Qwen3.6-35B · :8080"]
C["MLX code<br/>Qwen3-Coder-30B · :8081"]
O["Ollama fallback · :11434"]
end
TOOLS --> RAG["📚 LibraryBrain RAG · :8765"]
API -.expose.-> MCPS["📡 Serveur MCP Klody · :8083<br/>(Cline · Zed · Continue le consomment)"]
| # | Feature | Détail |
|---|---|---|
| 1 | 100 % local & privé | MLX sur Apple Silicon (Qwen3.6-35B-A3B cerveau, Qwen3-Coder-30B code). Zéro appel cloud par défaut. |
| 2 | Routeur adaptatif | classifie chaque prompt → 3 difficultés × 12 task_types (edit, refactor, bug_fix, feature, explain, self_dev, review, test_gen, security, docs, perf, migrate) → budget d'itérations + planner + Best-of-N (F1≈0,85). |
| 3 | Boucle qui va au bout | auto-continue quand la tâche est actionnable ; cliquet de continuation ("ok/vas-y" réutilise le routage). |
| 4 | Sandbox isolé multi-racines | venv jetable par racine, ALLOWED_ROOTS, exec auto après write (py_compile/pytest). |
| 5 | Client MCP | consomme n'importe quel serveur MCP ; outils exposés au LLM sous mcp__<srv>__<outil>. |
| 6 | Serveurs MCP fournis | Gmail (IMAP/SMTP) + Web (fetch/search lecture seule, anti-SSRF) — branchés par une ligne de .env. |
| 7 | Serveur MCP Klody | Klody = plateforme pour d'autres agents (Cline, Zed, Continue.dev). |
| 8 | Retrieval code-aware | tree-sitter (symboles/refs) + embeddings bge-m3 (find_symbol, find_relevant_files). Python/JS/TS de base ; Rust/Go/Java/PHP en option (grammaires chargées dynamiquement). |
| 9 | Best-of-N + mémoire | N candidats T variés + action override ; conventions auto-détectées + mémoire d'erreurs. |
| Composant | Tech |
|---|---|
| Runtime | Python 3.11+ · FastAPI · WebSocket |
| LLM cerveau | MLX-LM — unsloth/Qwen3.6-35B-A3B-MLX-8bit (:8080, enable_thinking=false) |
| LLM code | MLX-LM — mlx-community/Qwen3-Coder-30B-A3B-Instruct-8bit (:8081) |
| LLM fallback | Ollama — qwen2.5-coder:32b (:11434) |
| Embeddings | Ollama — bge-m3 |
| RAG livres | LibraryBrain — sqlite-vec + FTS5 (:8765) |
| MCP | FastMCP — Klody client et serveur ; connecteurs Gmail/Web |
| UI graphique | klody-ui — Tauri 2 + React 19 + Tailwind 4 (repo) |
| Tests | pytest — 699 tests · coverage 78 % |
pip install mlx-lm # MLX-LM (Apple Silicon recommandé)
brew install ollama ripgrep # Ollama (embeddings + fallback), ripgrep (recherche)
pip install sqlite-vec # optionnel (LibraryBrain)# Cerveau MLX (MoE 35B / ~3B actifs, multimodal)
huggingface-cli download unsloth/Qwen3.6-35B-A3B-MLX-8bit
# Spécialiste code (optionnel, port 8081)
huggingface-cli download mlx-community/Qwen3-Coder-30B-A3B-Instruct-8bit
# Embeddings (requis pour le retrieval)
ollama serve && ollama pull bge-m3git clone https://github.com/klodynlov/klody-code-ai.git
cd klody-code-ai && python3.11 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # puis éditer (voir ci-dessous)BACKEND=mlx
MLX_BASE_URL=http://localhost:8080/v1
MLX_MODEL=unsloth/Qwen3.6-35B-A3B-MLX-8bit
MLX_CHAT_TEMPLATE_ARGS='{"enable_thinking": false}' # requis pour Qwen3.6 (thinking)
PROJECT_ROOT=/Users/ton-nom/mon-projet # racine principale du sandbox
# ALLOWED_ROOTS=/Users/ton-nom/Projets:/Users/ton-nom/work # racines supplémentaires
MAX_ITERATIONS=25 # plafond boucle ReAct
# Connecteurs MCP (optionnels) — Klody les découvre au démarrage
# KLODY_MCP_SERVERS={"gmail":"http://127.0.0.1:8084/mcp","web":"http://127.0.0.1:8085/mcp"}./scripts/start-mlx.sh # 1. cerveau MLX (~30-60s de chargement)
ollama serve # 2. embeddings
python main.py # 3. CLI Rich (--resume / --session <id>)
python api/server.py # 4. (option) API WebSocket pour l'UI Tauri
./scripts/start-klody-mcp.sh --http # 5. (option) exposer Klody en serveur MCP (:8083)
# Connecteurs MCP (option) :
./scripts/start-gmail-mcp.sh --http # Gmail (:8084) — voir .env.example
./scripts/start-web-mcp.sh --http # Web (:8085) — lecture seule| Catégorie | Outils |
|---|---|
| Fichiers (multi-racines) | read_file, write_file, list_files, search_in_files |
| Code-aware | find_symbol, find_references, find_relevant_files, code_graph, analyze_dependencies, generate_uml (diagramme de classes Mermaid depuis le code) |
| Exécution | execute_command, run_in_sandbox (venv jetable par racine), run_sql (SQLite local sandboxé, lecture seule par défaut) |
| Ops / runtime | docker_control (Docker : ps/images/inspect/logs/stats en lecture seule ; run ultra-contraint si activé), kubectl_control (introspection Kubernetes lecture seule : get, describe, logs, top…), git_control (Git : status, log, diff, show, blame… en lecture seule ; add/commit locaux si GIT_WRITE_ENABLED) |
| Web preview | preview_code (auto-CDN + overlay erreurs JS), preview_file, list_previews |
| GitHub | browse_repo, read_github_file, index_github_repo, clone_github_repo, extract_best_practices, create_project |
| Audio | analyze_audio, edit_wav, mix_stems, generate_silence, convert_format, get_waveform_data |
| Génération | generate_uml (diagramme de classes Mermaid), scaffold_api (squelette CRUD : REST FastAPI ou GraphQL Strawberry), scaffold_sdk (client Python typé httpx), scaffold_nosql (repository MongoDB pymongo) |
Musique — composition (mcp__klodymusic__*) |
evaluer_tessiture, suggerer_tonalites, harmoniser, suggerer_accords, analyser_progression, reharmoniser, moduler, melodie_vers_midi, generer_basse, harmonies_vocales, idees_chanson, composer_demo |
Musique — mixage (mcp__klodymusic__*) |
recommander_eq, detecter_masquage, analyser_balance_tonale, recommander_compression, recommander_saturation (dérivés des mesures objectives d'audio_analysis : LUFS, spectre, largeur stéréo, crest) |
Musique — chant (mcp__klodymusic__*) |
evaluer_tessiture, analyser_justesse (écart en cents vs gamme), recommander_autotune (gamme/vitesse/force), harmonies_vocales |
Musique — sound design (mcp__klodymusic__*) |
generer_preset_synth (patch synthé agnostique par rôle/caractère), organiser_banque (rangement de samples par catégorie) |
| Musique — DAW / voix | mcp__reaper__* (pistes, FX, bus/sends, MIDI, régions, rendu stems, chaîne vocale, arrangement), mcp__vocalbrain__* (génération/entraînement de chant) |
| 🖥️ macOS (Apple Silicon) | run_applescript, spotlight_search, run_shortcut (HomeKit/Automator), list_shortcuts, reveal_in_finder |
| 🏠 Maison / IoT | mqtt_publish, mqtt_subscribe (ESP32, Raspberry Pi, Home Assistant, pont HomeKit) |
| 🧹 Automatisation | batch_rename, organize_directory, backup_directory, sync_directories (sandboxés, dry_run par défaut) |
| 🔨 Toolsmithing | scaffold_tool (script, cli, api, mcp_server, workflow, pipeline, klody_plugin, web_interface), list_tool_kinds |
| RAG / Skills | search_books, learn_from_books, get_skills, save_skill, list_skills, delete_skill |
| Mémoire | remember_fact, forget_fact |
| Connecteurs MCP | mcp__gmail__* (8 outils), mcp__web__* (fetch_url, web_search), + tout serveur MCP branché |
Le module le plus puissant : plutôt que de seulement utiliser des outils, Klody en construit de neufs, prêts à l'emploi et livrés avec leur test.
scaffold_tool(kind="mcp_server", name="capteurs maison", target_dir="~/Projets")
→ capteurs_maison/capteurs_maison_server.py (serveur MCP FastMCP)
capteurs_maison/test_capteurs_maison_server.py
capteurs_maison/requirements.txt + README.md
kind |
Produit |
|---|---|
python_script |
script CLI autonome (argparse) + test |
cli |
CLI multi-commandes (sous-commandes) + test |
api |
API FastAPI (health + echo) + test TestClient |
mcp_server |
serveur MCP FastMCP branchable dans Klody + test |
workflow |
orchestrateur d'étapes séquentielles + test |
pipeline |
pipeline ETL (extract → transform → load) + test |
klody_plugin |
plugin outil Klody (schéma registry + handler) |
web_interface |
interface web statique autonome (HTML + JS) |
- Sandbox fichiers : accès limité aux racines autorisées (
PROJECT_ROOT+ALLOWED_ROOTS) ;..//symlinks bloqués ; fichiers sensibles refusés partout (.env .key .pem .p12 .pfx .cer .crt .ppk .p8) ; 1 Mo max/écriture. - Sandbox exécution : confirmation en TTY ; blocklist pré-confirmation (
sudo,rm -rf /,mkfs, exfil SSH/AWS…) ;run_in_sandboxdans un venv jetable isolé. - SQL sandboxé (
run_sql) : base SQLite confinée aux racines autorisées, lecture seule par défaut (SQL_WRITE_ENABLED) ; authorizer sqlite3 default-deny,ATTACH/VACUUM INTO/load_extensionbloqués, verrouSQLITE_LIMIT_ATTACHED=0, anti-DoS (limites + échéance wall-clock), une seule instruction par appel. Contrôles issus d'un threat-model adversarial. - Ops en lecture seule (
docker_control,kubectl_control,git_control) : introspection uniquement (Docker : ps/images/inspect/logs/stats… ; k8s : get/describe/logs/top… ; Git : status/log/diff/show/blame…), aucune mutation ;subprocessen argv (pas de shell), sous-commandes/verbes hardcodés, entrées (cible, resource, name, namespace, ref, fichier) validées par charset strict — pas d'injection de commande ni de flag (-o jsonpath,--kubeconfig,--output…) ; dépôt Git confiné aux racines autorisées ; sortie plafonnée, timeout borné. Les mutations Git (add/commit, locales et réversibles) sont désactivées par défaut (GIT_WRITE_ENABLED) ;push/pullet les opérations destructives (reset/checkout/clean/rebase) restent hors de l'outil. Ledocker run(mutation) est doublement borné —DOCKER_WRITE_ENABLEDet une allowlist d'images non vide — et impose un durcissement figé (aucun flag utilisateur :--network none,--cap-drop ALL,no-new-privileges, limites ressources, pas de montage) ;build/exec/rmrestent exclus. - Web en lecture seule :
fetch_url/web_searchen GET, http/https only, anti-SSRF (IP privées/loopback/link-local refusées, y compris via redirection), taille plafonnée. - Pilotage macOS : garde plateforme (hors macOS → message clair, jamais d'exception) ; blocklist AppleScript (suppression, vidage corbeille, extinction,
do shell script, contrôle UI synthétique refusés) ;reveal_in_finder/Spotlight confinés aux racines autorisées ; timeouts + sortie plafonnée. - Automatisation & toolsmithing : opérations de masse en
dry_runpar défaut (montrent le plan avant d'agir) ; fichiers sensibles exclus partout ; destinations confinées aux racines autorisées ; refus d'écraser un dossier existant. MQTT borné (écoute à timeout dur, payload plafonné, broker local par défaut). - Secrets :
.envgitignoré, jamais hardcodés ni loggés. Commits signés (ED25519), branch protection surmain. - CI : bandit (HIGH), gitleaks, pip-audit
--strict, gate coverage 75 %, snapshots contrat MCP/OpenAPI.
python -m pytest tests/ -q # 699 passing
BACKEND=mlx python -m bench.run --category easy # bench reproductible
BACKEND=mlx python -m bench.router_eval # précision du routeur (F1 macro)| Commande | Description |
|---|---|
/help |
Aide |
/sessions |
Liste / charge une session passée |
/memory |
Mémoire courte + souvenirs long terme |
/model · /model <id> |
Modèle actif / change à chaud |
/skills |
Compétences mémorisées |
/exit |
Quitte |
python main.py --resume # reprend la dernière session
python main.py --session <id-court> # reprend une session précise| Symptôme | Cause / solution |
|---|---|
APIConnectionError (MLX) |
Lancer ./scripts/start-mlx.sh |
Connection refused (Ollama) |
ollama serve (requis pour les embeddings bge-m3) |
model not found (MLX) |
huggingface-cli download unsloth/Qwen3.6-35B-A3B-MLX-8bit |
| Le modèle « réfléchit » sans répondre | Qwen3.6 est thinking → MLX_CHAT_TEMPLATE_ARGS='{"enable_thinking": false}' dans .env |
SandboxViolation |
Le chemin doit être sous PROJECT_ROOT/ALLOWED_ROOTS (chemins absolus existants) |
| Outil MCP absent | Vérifier KLODY_MCP_SERVERS + serveur lancé, puis redémarrer le backend (config lue au boot) |
| UI Tauri figée | Cmd+Shift+R ; vérifier python api/server.py sur :8000 |
- 📐 Étude de cas technique — les décisions d'ingénierie (routeur, MCP, sandbox, la saga
max_tokens). - 🛠️ OPS — exploitation, services permanents (LaunchAgents).
- 💼 Pour les entreprises — agents IA privés / local-first.
MIT © 2026 klodynlov